0
0
Kotlinprogramming~10 mins

In variance (contravariance) in Kotlin - Step-by-Step Execution

Choose your learning style9 modes available
Concept Flow - In variance (contravariance)
Start: Function expects Consumer<T>
Use Consumer<in T> to accept T or its supertypes
Pass Consumer<SuperType> where Consumer<T> expected
Function calls consumer.accept(T)
Consumer handles T or subtype safely
End
Shows how contravariance allows passing a consumer of a supertype where a consumer of a subtype is expected, enabling safe input.
Execution Sample
Kotlin
interface Consumer<in T> {
    fun accept(item: T)
}

fun feedConsumer(consumer: Consumer<String>) {
    consumer.accept("Hello")
}
Defines a Consumer interface with contravariant type T and a function that feeds a String to the consumer.
Execution Table
StepActionType of consumer passedaccept() argument typeResult
1Call feedConsumer with Consumer<Any>Consumer<Any>StringAllowed: Consumer<Any> accepts String
2Inside feedConsumer, call consumer.accept("Hello")Consumer<Any>StringPrints or processes "Hello"
3Call feedConsumer with Consumer<String>Consumer<String>StringAllowed: exact match
4Inside feedConsumer, call consumer.accept("Hello")Consumer<String>StringPrints or processes "Hello"
5Call feedConsumer with Consumer<Int>Consumer<Int>StringError: Consumer<Int> cannot accept String
6Execution stops due to type mismatch---
💡 Cannot pass Consumer<Int> where Consumer<String> expected because Int is not a supertype of String
Variable Tracker
VariableStartAfter Step 1After Step 3After Step 5
consumerundefinedConsumer<Any>Consumer<String>Consumer<Int> (invalid)
accept argumentundefined"Hello" (String)"Hello" (String)Type mismatch
Key Moments - 2 Insights
Why can we pass Consumer<Any> to a function expecting Consumer<String>?
Because Consumer is declared with 'in' (contravariant), it can accept supertypes of String, so Consumer<Any> can safely consume Strings (see execution_table rows 1 and 2).
Why can't we pass Consumer<Int> to feedConsumer expecting Consumer<String>?
Consumer<Int> expects Int inputs, but feedConsumer passes a String, causing a type mismatch (see execution_table row 5). Contravariance only allows supertypes, not unrelated or subtypes.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what type of consumer is allowed to be passed to feedConsumer?
AConsumer<Double>
BConsumer<Int>
CConsumer<Any>
DConsumer<List<String>>
💡 Hint
Check execution_table rows 1 and 5 to see which consumer types are accepted or rejected.
At which step does the execution stop due to a type mismatch?
AStep 5
BStep 4
CStep 2
DStep 3
💡 Hint
Look at execution_table row 5 where Consumer is passed and causes an error.
If we remove 'in' from Consumer<T>, what happens when passing Consumer<Any> to feedConsumer?
AIt works the same
BIt causes a type error
CConsumer<Any> becomes Consumer<String>
DThe function accepts any consumer
💡 Hint
Contravariance ('in') allows passing supertypes; removing it disables this flexibility (see concept_flow).
Concept Snapshot
In variance (contravariance) in Kotlin uses 'in' keyword.
It allows a generic type Consumer<in T> to accept T or any supertype.
This means you can pass Consumer<Any> where Consumer<String> is expected.
Useful for input-only generic types.
Contravariance ensures type safety when consuming values.
Full Transcript
This visual trace shows how Kotlin's in variance (contravariance) works with a Consumer interface. The Consumer interface is declared with 'in T', meaning it can accept T or any supertype of T. The feedConsumer function expects a Consumer<String>. Thanks to contravariance, you can pass a Consumer<Any> safely because Any is a supertype of String. The execution table shows steps where Consumer<Any> and Consumer<String> are accepted, but Consumer<Int> is rejected because Int is not a supertype of String. Variable tracking shows how the consumer variable changes type across calls. Key moments clarify why contravariance allows supertypes but not unrelated types. The quiz tests understanding of allowed types, error steps, and the effect of removing 'in'. This helps beginners see how contravariance enables safe input flexibility in Kotlin generics.