Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A generic function in Kotlin is a function parameterized over one or more types. By declaring type parameters, the function defers the specification of the exact data types it operates on until it is invoked, enforcing compile-time type safety without relying on type casting or the Any supertype.

Syntax and Declaration

Type parameters are declared inside angle brackets < > immediately preceding the function name. Once declared, these type parameters can be utilized as return types, parameter types, or variable types within the function’s lexical scope.
fun <T> functionName(parameter: T): T {
    return parameter
}
Multiple type parameters are separated by commas:
fun <T, R> transform(input: T, operation: (T) -> R): R {
    return operation(input)
}

Type Inference and Instantiation

When a generic function is invoked, the Kotlin compiler utilizes type inference to determine the type arguments based on the provided parameters. If the compiler cannot infer the type (e.g., when the type parameter is only used as a return type), it must be explicitly specified at the call site.
fun <T> singletonList(item: T): List<T> = listOf(item)

// Implicit type inference (T is inferred as Int)
val inferredList = singletonList(42)

// Explicit type specification
val explicitList = singletonList<String>("Kotlin")

Generic Extension Functions

Generics are frequently applied to extension functions to operate on parameterized receiver types. The type parameter must be declared before the receiver type in the function signature.
fun <T> Iterable<T>.customFilter(predicate: (T) -> Boolean): List<T> {
    val destination = ArrayList<T>()
    for (element in this) {
        if (predicate(element)) destination.add(element)
    }
    return destination
}

Type Constraints (Upper Bounds)

By default, the implicit upper bound of a type parameter T is Any?, meaning it accepts any nullable or non-nullable type. To restrict the type parameter to a specific hierarchy, an upper bound is defined using a colon :. The compiler will reject any type argument that is not a subtype of the specified bound.
// T is constrained to Number or its subtypes
fun <T : Number> sum(a: T, b: T): Double {
    return a.toDouble() + b.toDouble()
}

Multiple Type Constraints

If a type parameter must satisfy more than one upper bound, the constraint cannot be declared inline. Instead, Kotlin requires a where clause appended to the end of the function signature.
// T must be a subtype of both CharSequence and Comparable
fun <T> sortAndPrint(list: List<T>) where T : CharSequence, T : Comparable<T> {
    val sorted = list.sorted()
    println(sorted)
}

Reified Type Parameters and Type Erasure

Kotlin generics are subject to type erasure on the JVM; type arguments are discarded at compile time, making it impossible to perform runtime type checks (e.g., value is T) or access class metadata (e.g., T::class.java) on standard generic parameters. To bypass type erasure, a generic function can be marked as inline and its type parameter marked as reified. The compiler inlines the function bytecode at the call site and replaces the type parameter with the actual compiled class, preserving the type identity at runtime.
inline fun <reified T> isInstanceOf(value: Any): Boolean {
    // Valid at runtime only because T is reified
    return value is T 
}

inline fun <reified T> getJavaClass(): Class<T> {
    return T::class.java
}
Master Kotlin with Deep Grasping Methodology!Learn More