open class A
class B: A()
fun <T> copy(src: MutableList<T>, dst: MutableList<T>) {
for (i in 0 until src.size) {
dst.add(i, src[i])
}
}
For the above mentioned code I understand that copy function
expects both type parameters of exactly same type. With a slight modification copy(src: MutableList<T>, dst: MutableList<in T>)
notice the in keyword, I am saying that src
must be of exactly type T
but destination can be of type T
or any super type of T.
For the above modified code, I am able to call the method as following,
fun main(args: Array<String>) {
val l1 = mutableListOf(B(), B())
val l2 = mutableListOf<A>()
copy(l1, l2)
} // main
The above copy(l1, l2)
does not work if I remove in
from the destination (understood).
My question is, I am able to call the function without any error if update the function parameter src
to accept out
projection of the list. e.g.
fun <T> copy(src: MutableList<out /*notice out here*/ T>, dst: MutableList<T>) {
for (i in 0 until src.size) {
dst.add(i, src[i])
}
}
In this case, I am not able to understand what goes on under the hood.Can any one explain please?
Note that this is just an example from the book. I know I can use List
instead of immutable list in src
out
here works symmetrically to in
:
in keyword, I am saying that src must be of exactly type T but destination can be of type T or any super type of T
So now you are saying that src
must be a MutableList
of type T
or any subtype of T
, while dst
must be a MutableList
of exactly type T
.
So when you have l1: MutableList<B>
and l2: MutableList<A>
, the compiler infers the type parameter in copy(l1, l2)
as copy<A>(l1, l2)
, and it typechecks: MutableList<B>
is a subtype of MutableList<out A>
.
Because you are only using out
-compatible operations on src
, and only in
-compatible operations on dst
, as @s1m0nw1 says it makes perfect sense to include both modifiers.