Generic Classes and Functions

Why Generics?

Generics let one class or function work with many types while keeping type safety. List<String> and List<Int> are the same List code with a different type parameter. Without generics you would use Any and cast everywhere.

Example

class Box<T>(val value: T) {
    fun describe() = "Box contains $value"
}

fun <T> printAll(items: List<T>) {
    items.forEachIndexed { i, item -> println("$i: $item") }
}

fun <K, V> pairOf(key: K, value: V): Pair<K, V> = key to value

fun main() {
    val intBox = Box(42)               // T inferred as Int
    val strBox = Box<String>("hello")  // explicit
    println(intBox.describe())
    println(strBox.value.uppercase()) // no cast needed
    printAll(listOf("Kotlin", "Java"))
    println(pairOf("id", 7))
}

Output

Box contains 42
HELLO
0: Kotlin
1: Java
(id, 7)

A Generic Stack

Example

class Stack<T> {
    private val items = mutableListOf<T>()
    fun push(item: T) = items.add(item)
    fun pop(): T? = items.removeLastOrNull()
    fun peek(): T? = items.lastOrNull()
    val size get() = items.size
}

fun main() {
    val history = Stack<String>()
    history.push("Home"); history.push("Search"); history.push("Product")
    println("Back from ${history.pop()} to ${history.peek()}")
    println("Screens left: ${history.size}")
}

Output

Back from Product to Search
Screens left: 2