What is Variance in Kotlin Generics Explained Simply
variance controls how generic types relate to each other when their type parameters differ. It uses out (covariant) and in (contravariant) keywords to allow safe type substitution, making generic types flexible and type-safe.How It Works
Imagine you have a box that can hold items of a certain type. Variance in Kotlin tells us how we can safely replace that box with another box holding a related type. For example, if you have a box of apples, can you use it where a box of fruits is expected? Variance answers this question.
Kotlin uses two main keywords: out and in. The out keyword means the generic type only produces or returns values (like a fruit basket you only take fruits from). This is called covariance and allows you to use a more specific type where a general type is expected.
The in keyword means the generic type only consumes or accepts values (like a basket where you only put fruits in). This is contravariance and allows you to use a more general type where a specific type is expected. This system keeps your code safe and flexible.
Example
This example shows how out and in work in Kotlin generics.
open class Fruit class Apple : Fruit() class Box<out T>(val item: T) { fun getItem(): T = item } fun feedFruit(box: Box<Fruit>) { println("Feeding fruit: ${box.getItem()}") } fun main() { val appleBox: Box<Apple> = Box(Apple()) feedFruit(appleBox) // Works because Box is covariant with 'out' }
When to Use
Use variance when you want to make your generic classes or interfaces more flexible and safe with type substitutions. Use out when your generic type only produces or returns values, like a read-only list or a data source. Use in when your generic type only consumes or accepts values, like a consumer or a sink.
For example, if you have a function that only reads data from a collection, declare the collection as out to accept subtypes safely. If you have a function that only writes data into a collection, declare it as in to accept supertypes safely.
Key Points
- Covariance (
out): allows a generic type to produce values and be substituted with its subtypes. - Contravariance (
in): allows a generic type to consume values and be substituted with its supertypes. - Variance helps keep code type-safe while allowing flexible use of generic types.
- Use
outfor read-only or producer roles, andinfor write-only or consumer roles.