Generic classes and functions
A generic type has a placeholder, conventionally T, that the caller fills in. List<String> and List<Int> are the same class with different type arguments, and the compiler checks every use. Kotlin usually infers the argument, so you rarely write it out.
class Stack<T> {
private val items = mutableListOf<T>()
fun push(item: T) { items.add(item) }
fun pop(): T? = items.removeLastOrNull()
val size: Int get() = items.size
}
fun <T> firstOrDefault(xs: List<T>, default: T): T = if (xs.isEmpty()) default else xs[0]
fun main() {
val s = Stack<String>()
s.push("a"); s.push("b")
println(s.pop())
println(s.size)
println(firstOrDefault(listOf(3, 4), 0))
println(firstOrDefault(emptyList(), "none"))
}b
1
3
noneAdd a peek(): T? that returns the top item without removing it.
An upper bound (<T : Comparable<T>>) restricts which types are allowed, and in return lets you call the bound's methods on T. For several bounds, use a where clause.
fun <T : Comparable<T>> largest(xs: List<T>): T {
var best = xs[0]
for (x in xs) if (x > best) best = x
return best
}
fun <T> describe(x: T): String where T : CharSequence, T : Comparable<T> =
"$x has ${x.length} chars"
fun main() {
println(largest(listOf(3, 9, 4)))
println(largest(listOf("pear", "apple", "zucchini")))
println(describe("kotlin"))
}9
zucchini
kotlin has 6 charsA type that does not satisfy the bound
fun <T : Comparable<T>> maxOf3(a: T, b: T, c: T): T = maxOf(a, maxOf(b, c))
class Box(val v: Int)
fun main() = println(maxOf3(Box(1), Box(2), Box(3)))Main.kt:5:22: error: cannot infer type for type parameter 'T'. Specify it explicitly.
fun main() = println(maxOf3(Box(1), Box(2), Box(3)))
^^^^^^
Main.kt:5:29: error: argument type mismatch: actual type is 'Box', but 'Comparable<uninferred T (of fun <T : Comparable<T>> maxOf3)>' was expected.
fun main() = println(maxOf3(Box(1), Box(2), Box(3)))
^^^^^^Box does not implement Comparable<Box>, so the compiler cannot promise that maxOf can compare two of them.
Implement Comparable on the class, or pass a comparator-based function such as maxOf(a, b, c, compareBy { it.v })... or simply compare the property you care about.
fun <T : Comparable<T>> maxOf3(a: T, b: T, c: T): T = maxOf(a, maxOf(b, c))
class Box(val v: Int) : Comparable<Box> {
override fun compareTo(other: Box) = v.compareTo(other.v)
}
fun main() = println(maxOf3(Box(1), Box(2), Box(3)).v)