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
