jskierbi
5/30/2017 - 3:08 PM

Kotlin Generics and variance

Kotlin Generics and variance

// https://kotlinlang.org/docs/reference/generics.html
// The Existential Transformation: Consumer in, Producer out! :-)

// Covariance (producer)
val covariantList: List<out Animal> = listOf<Lion>() // In Java: List<? extends Animal>
val animal: Animal = covariantList.get(0) // Ok
covariantList.put(Animal()) // Compilation error - compiler doesn't know exact 
			    // type of covariantList and is not sure if 
		      	    // it can store Animal (not all animals are lions)

// Contravariance (consumer)
val contravariantList: List<in Animal> = listOf<Any>() // In Java: List<? super Animal>
val animal: Animal = contravariantList.get(0) 	// Compilation error - list can store 
					        // other objects than Animals as well
contravariantList.put(Animal()) // Ok
// Producer is covariant in T
// Class body can only return T, not take T as parameter
class Producer<out T> {
	fun produce() : T // ok
	fun consume(item: T) // compile error
}

// Then it's possible to:
fun covariantExample(x: Producer<String>) {
	val y: Producer<Any> = x // Allowed, producer is covariant in T
}

// Consumer is contravariant in T
// Class body can only consume T (take as parameter), not return it
class Consumer<in T> {
	fun produce(): T // Compilation error
	fun consume(item: T) // ok
}

// Then it's possible to:
fun contravariantExample(x: Consumer<Number>) {
	val y: Consumer<Double> = x // Allowed, Consumer is contravariant in T
}
// Type projection: "from" is not simply an array, but a restricted (projected) 
// one: we can only call those methods that return the type parameter T, 
// in this case it means that we can only call get()
fun <T> copy(from: Array<out T>, to: Array<in T>) {
	// ...
}