KOTLIN / CHAPTER 11

Generic APIs and variance

Advanced

Express reusable producer and consumer capabilities safely.

By the end of this chapter

  • Use type parameters for relationships
  • Distinguish producers from consumers
  • Avoid unchecked casts as an API design

The idea

A type parameter connects the types of related inputs and outputs. A function that returns the first element as T preserves information that would be lost by returning Any. Constraints limit the operations available inside the generic implementation. They should reflect the actual algorithm: comparing elements for order requires more than simply accepting arbitrary values of T.

Variance describes safe substitution between parameterized types. A producer that only supplies T can declare out T, allowing a producer of strings to be viewed as a producer of Any. A consumer can use in T when it only accepts values. Mutable collections both read and write their element type, so treating a MutableList<String> as MutableList<Any> would allow insertion of an incompatible value.

Kotlin example
interface Source<out T>{fun next():T}
class WordSource:Source<String>{override fun next()="ready"}
fun main(){val source:Source<Any> = WordSource();println(source.next())}
Result
ready

The producer exposes only returned values, so a string-producing source can safely satisfy a consumer expecting Any results.

Try it yourself

Write fun <T> firstOrNull(values: List<T>): T? and define the empty-input result.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

Why is assigning MutableList<String> to MutableList<Any> unsafe?