androidengineers.Book a session

Generics and Type Parameters

Variance: in/out (use-site & declaration-site)

article15 minMedium

Variance follows the direction values move

A producer returning T can often be covariant with out T. A consumer accepting T can often be contravariant with in T. A mutable container that both accepts and returns values generally needs invariance.

interface Source<out T> { fun next(): T }
interface Sink<in T> { fun accept(value: T) }

fun consume(source: Source<String>, sink: Sink<Any>) {
    val broadSource: Source<Any> = source
    val textSink: Sink<String> = sink
    textSink.accept(broadSource.next().toString())
}

A source of strings can safely stand in for a source of arbitrary objects because every produced string is an object. A sink capable of accepting any object can accept strings. Allowing a mutable list of strings to be treated as a mutable list of objects would permit inserting an integer into it.

Exercise

Implement a string source and an object sink. Try reversing both assignments and inspect the compiler errors.

Check: explain variance through permitted reads and writes instead of memorizing only the keywords.

Reference: Variance

YOUR LEARNING JOURNEY

0 of 110 available lessons completed

Progress saved in this browser. No account needed.
Variance: in/out (use-site & declaration-site) | Kotlin Core Programming | Android Engineers