Sobes.tech
Junior

What types of generics do you know?

sobes.tech AI

Answer from AI

Invariant, covariant, and contravariant.

  • Invariance: The type List<A> is not a subtype of List<B> and vice versa, even if A is a subtype of B. The type remains exact.
  • Covariance (out): Allows using subtypes. List<A> is a subtype of List<B> if A is a subtype of B. Used for output parameters (return values).
fun foo(list: List<out Number>) {
    // Can read from the list (Number, Double, Int, etc.)
    val number: Number = list[0]
    // Cannot add to the list (unknown what type of elements are expected)
    // list.add(1) // Compilation error
}
  • Contravariance (in): Allows using supertypes. List<B> is a subtype of List<A> if A is a subtype of B. Used for input parameters (arguments).
fun foo(comparable: Comparable<in String>) {
    // Can pass String (or its supertypes)
    val result = comparable.compareTo("hello")
    // Cannot get results of type String (unknown what type of result)
    // val str: String = comparable.compareTo("world") // Compilation error
}

In Kotlin, these concepts are implemented using out and in annotations on type parameters. In Java, wildcards (? extends for covariance and ? super for contravariance) are used.

Type Purpose Kotlin keyword Wildcard (Java) Reading allowed Writing allowed
Invariant Exact type match No No Yes Yes
Covariant Use of subtypes (producer - "out") out ? extends T Yes No
Contravariant Use of supertypes (consumer - "in") in ? super T No Yes