Preserve type relationships with generics
A type parameter describes a relationship between inputs, stored values, and outputs. It prevents the caller from recovering type information through unsafe casts.
class Box<T>(val value: T)
fun <T> duplicate(value: T): Pair<T, T> = value to value
fun main() {
val box = Box("Kotlin")
check(box.value.length == 6)
check(duplicate(25) == (25 to 25))
}
T does not mean any operation is available. Without a bound, the function can use only operations valid for its upper bound. A nullable type can be supplied unless you constrain it with T : Any.
Prefer a generic API when the same algorithm works independently of a concrete type. Replacing every domain type with T can obscure useful constraints rather than improve reuse.
Exercise
Implement firstOrFallback(values, fallback) with one type parameter. Test strings, integers, and empty input.
Check: the return type should preserve the relationship to the collection and fallback without an as cast.