// 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")))
}
Create a free account and build your private vault. Share publicly whenever you want.