Generics in Kotlin allow for the creation of universal and type-safe data structures and functions. The main feature: Kotlin implements the generics type system at compile-time, like Java, but with stricter type safety and extended syntax for variance (covariance and contravariance).
Limitations of generics:
T() is prohibited).Variance:
Example of covariance:
interface Producer<out T> { fun produce(): T }
Example of contravariance:
interface Consumer<in T> { fun consume(item: T) }
Difference from Java:
out instead of ? extends, in instead of ? super).?, only in/out).Question: "Can you declare an array of arrays in Kotlin (Array<Array<Int>>) as Array<out Array<Int>> and what will happen if you try to write to such an array?"
Answer: Yes, you can declare it as Array<out Array<Int>>, but such an array becomes read-only:
val arr: Array<out Array<Int>> = Array(1) { Array(1) { 0 } } arr[0] = arrayOf(1, 2, 3) // Compilation error!
Attempting to write a value will result in an error — a generic array with an out parameter does not allow writing elements, as this would violate type safety.
Story
The team tried to create an array of generic objects with an out parameter type, and then attempted to put values into it via set(index, value). The code compiled, but caused runtime errors, and several functions became non-working.
Story
Once during the migration of a library from Java to Kotlin, wildcards (? extends ...) were left, and in Kotlin, the types were simply copied without changing to out/in. The result — compilation failed, and during "traversing" the error occurred at runtime, complicating the debugging process.
Story
Used in/out variance with a custom class, but mixed up the modifiers, declaring interface Stack<in T> instead of Stack<out T>. This led to the impossibility of returning elements from the stack: the method signature violated the system out/in contract.