A variance annotation is a modifier applied to a type parameter or type argument of a generic, in order to declare its variance.
Kotlin defines two variance annotations in its grammar: out and in.
out
The out modifier is used to declare a type parameter as being covariant. For example:
class Box<out T>(private val item: T) {
fun getItem(): T = item
}
With the out variance annotation declared on the type parameter T in this class, subtyping rules can now be applied to Boxes of different types. For example:
val integer: Box<Int> = Box(1)
val number: Box<Number> = integer
Notice how number, although declared as a Box<Number>, refers to an object of type Box<Int>. In other words, Box<Int> is now a subtype of Box<Number>.
Also note that in our class, T is only ever used in the “out” position - it’s only ever returned from a function. By declaring it to be out, the compiler will no longer allow the class to accept a function argument of type T (other than within the constructor).
in
The in modifier is used to declare a type parameter as being contravariant. For example:
class Box<in T>(private var item: T) {
fun setItem(item: T) {
this.item = item
}
}
The in variance annotation on type parameter T causes subtyping rules to apply to Box in the opposite direction to the subtyping rules of the classes that it wraps. For example:
val number: Box<Number> = Box(1)
val integer: Box<Int> = number
val double: Box<Double> = number
Because of the in modifier, Box<Number> is now a subtype of both Box<Int> and Box<Double>.
By adding in to the type parameter, the compiler will only ever allow us to use the type parameter in the “in” position - as a function argument. It can never be returned by a function.
No variance annotation
If no variance annotation is declared on a type parameter, then by default, the it’ll be invariant. For example:
class Box<T>(private var item: T) {
fun getItem(): T = item
fun setItem(item: T) {
this.item = item
}
}
In this case, no subtyping rules will be applied to Box, so neither Box<Number> nor Box<Int> is a subtype of the other.