Careeroza
Use-Site Variance and Star Projection
Use-Site Variance
MutableList is invariant, because it both reads and writes. In a single function you can still say "I will only read" (out) or "I will only write" (in). This is called a type projection.
Example
fun copy(from: MutableList<out Number>, to: MutableList<in Number>) {
for (n in from) to.add(n) // read from 'from', write to 'to'
}
fun main() {
val ints = mutableListOf(1, 2, 3)
val all = mutableListOf<Any>("start")
copy(ints, all)
println(all)
}Output
[start, 1, 2, 3]
Star Projection
Example
List<*> means "a list of some type I do not know". You can read elements as Any? but cannot add to it.
fun printSize(list: List<*>) {
println("${list.size} items, first = ${list.firstOrNull()}")
}
fun main() {
printSize(listOf(1, 2, 3))
printSize(listOf("a", "b"))
printSize(emptyList<Double>())
}Output
3 items, first = 1 2 items, first = a 0 items, first = null
Type Erasure
Note: Generic type arguments are erased at runtime on the JVM: if (x is List<String>) is not allowed, only is List<*>. Inline functions with reified type parameters (advanced level) work around this - that is how filterIsInstance<T>() works.