Kotlin

Variance — in vs out

admin by @admin ADMIN
1h ago
Jun 1, 2026
Public
0 0 up · 0 down Sign in to vote
`out T` (covariant) → producer of T; can be assigned to a wider type. `in T` (contravariant) → consumer of T; can be assigned to a narrower type. Without modifiers, generics are invariant (strict match).
Kotlin
Raw
// Covariant — produces T. Read-only.
interface Producer<out T> {
    fun produce(): T
}

// Contravariant — consumes T. Write-only.
interface Consumer<in T> {
    fun consume(item: T)
}

open class Animal(val name: String)
class Dog(name: String) : Animal(name)

fun main() {
    val dogProducer: Producer<Dog>    = object : Producer<Dog> { override fun produce() = Dog("Rex") }
    val animalProducer: Producer<Animal> = dogProducer        // ✓ Dog "is-a" Animal, so a Dog producer is an Animal producer

    val animalConsumer: Consumer<Animal> = object : Consumer<Animal> {
        override fun consume(item: Animal) { println(item.name) }
    }
    val dogConsumer: Consumer<Dog> = animalConsumer          // ✓ A consumer of Animal can consume Dogs

    // Use-site variance:  List<out Animal> — accept List<Dog>, List<Cat>, etc.
    fun printAll(items: List<Animal>) {
        for (a in items) println(a.name)
    }
    printAll(listOf(Dog("Rex"), Dog("Buddy")))
}
Tags

Save your own code snippets

Create a free account and build your private vault. Share publicly whenever you want.