0Pricing
Kotlin Academy · Lesson

Declaration-Site Variance: in and out

Use covariant (out) and contravariant (in) type parameters correctly.

The Variance Problem

In Kotlin, List<String> is a subtype of List<Any> because List is declared with out T. Without variance annotations, this would not hold.

val strings: List<String> = listOf("a", "b")
val anys: List<Any> = strings  // OK because List<out T>
// MutableList<String> is NOT a subtype of MutableList<Any>:
// val m: MutableList<Any> = mutableListOf("x") // compile error
fun main() { println(anys) }

Covariance with out

out T means the class can only produce T values (return them), never consume them. This makes Producer<Dog> a subtype of Producer<Animal>.

interface Producer<out T> {
    fun produce(): T
}
class DogProducer : Producer<String> {
    override fun produce() = "Woof!"
}
fun sound(p: Producer<Any>) = println(p.produce())
fun main() {
    val dog = DogProducer()
    sound(dog)  // OK: Producer<String> is a subtype of Producer<Any>
}

All lessons in this course

  1. Generic Functions and Type Constraints with where
  2. Declaration-Site Variance: in and out
  3. Star Projection and When to Use *
  4. Type Erasure and reified Type Parameters
← Back to Kotlin Academy