liveBook · Manning

Declaration-site variance

As explained in Kotlin in Action, 2E

Declaration-site variance specifies at a generic type declaration whether different instantiations are related as subtypes or supertypes based on their type arguments.

Declaration-site variance specifies subtype relationships for generic types at the class or interface declaration, so every use follows the same variance rule. It answers practical questions such as whether a List<String> can be passed where a List<Any> is expected. section 11.0

A covariant read-only list

val strings: List<String> = listOf("one", "two") val values: List<Any> = strings The second assignment works because Kotlin's read-only List is declared covariant. A List<String> is therefore a subtype of List<Any>: the list produces String values, and every String is also an Any. section 11.4

Declaration-site variance follows the direction in which a type parameter is used:

  • Covariance uses an out position: a generic type can produce values of its type parameter, making specialized instantiations usable as more general ones. section 11.4
  • Contravariance uses an in position: a generic type can consume values of its type parameter. Function types combine contravariant input with covariant output. section 11.4
  • Types that both produce and consume their type parameter, such as MutableList, cannot generally declare either direction of variance. section 11.3.5

Use-site variance handles an individual occurrence when a class cannot be variant in every context. For example, a mutable source can be viewed as MutableList<out T> when the function only reads from it, while a destination can use MutableList<in T> when the function only writes to it. section 11.3.5

/* Java */
public interface Stream<T> {
   <R> Stream<R> map(Function<? super T, ? extends R> mapper);
}

Java expresses comparable relationships with use-site wildcards such as ? super T and ? extends R on each occurrence. Kotlin places reusable variance declarations on the generic type itself, making client code more concise. section 11.3.5

How Kotlin in Action, 2E covers it

How deep it goes
Explains covariance, contravariance, producer-consumer restrictions, and use-site projections with collection and function examples.
Examples
Demonstrates List<String> as List<Any>, MutableList copy functions, type projections, and Java Stream.map wildcards.
What it assumes
Assumes familiarity with basic generic classes, functions, type arguments, and subtype relationships.
What you can do after
Apply it via Kotlin generic declarations and use-site projections when designing or calling producer and consumer APIs.
How it connects
Connects variance to generics, covariance, contravariance, use-site variance, Java wildcards, function types, and mutable collections.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.