Declaration-Site and Use-Site Variance

Using <out T> in a type declaration, as List does, is called “declaration-site variance”. The alternative is “use-site variance” — using <out T> for a function parameter.

For example, let’s try to clone some frogs:

open class Animal

class Frog : Animal()

class Axolotl : Animal()

fun <T> clone(input: MutableList<T>, output: MutableList<T>) {
  input.forEachIndexed { index, item -> output[index] = item}
}

fun main() {
  val input = mutableListOf(Frog(), Frog())
  val result = mutableListOf<Animal>(Axolotl(), Axolotl())
  
  clone(input, result)
  
  println(result)
}

clone() takes in two lists, and it assigns the values in the output list to be the same as the input list, on a per-index basis. This function should be performing some data validation, ensuring that the output list is the same length or longer than the input list, but we are skipping that to keep the example code shorter.

However, this code does not compile:

Type mismatch: inferred type is Animal but Frog was expected

The complaint is about the input parameters to clone(). We are passing into clone():

However, clone() is expecting both parameters to be of type T, but we are passing in two different (but related) types: Frog and Animal.

Logically, what we want clone() to do is fine. A Frog is an Animal, so we can take a bunch of Frog objects and assign them to Animal slots in a list.

Adding out to the use site indicates that we can accept the input MutableList to be of type T or any sub-type:

open class Animal

class Frog : Animal()

class Axolotl : Animal()

fun <T> clone(input: MutableList<out T>, output: MutableList<T>) {
  input.forEachIndexed { index, item -> output[index] = item}
}

fun main() {
  val input = mutableListOf(Frog(), Frog())
  val result = mutableListOf<Animal>(Axolotl(), Axolotl())
  
  clone(input, result)
  
  println(result)
}

That satisfies the compiler and makes logical sense: we can put an object of any Animal sub-type into an Animal slot in a list.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.