Reified Type Parameters
In this page:
inline fun <reified T> functionName(value: Any): Boolean {
return value is T // T is available at runtime
}
inline fun <reified T> typeName(): String? = T::class.simpleName
The Type Erasure Problem
On the JVM, generic type information is normally erased at runtime, so a regular generic function cannot check if (value is T) -- the compiler doesn't know what T actually is once compiled.
Example: The Type Erasure Problem
fun <T> describe(value: Any): String {
// Return `"Checking value: $value"` from this function
return "Checking value: $value"
}
// Entry point: execution of the program starts here
fun main() {
// Print `describe<String>("Kotlin")` to the console, with a trailing newline
println(describe<String>("Kotlin"))
}
Login to try C/C++/Java/PHP code in the editor
Reified Solves It with inline
Marking the type parameter reified on an inline function preserves the actual type at each call site, because the function's code (and the real type) get copied directly into the caller.
Example: Reified Solves It with inline
inline fun <reified T> isInstanceOf(value: Any): Boolean = value is T
// Entry point: execution of the program starts here
fun main() {
// Print `isInstanceOf<String>("Kotlin")` to the console, with a trailing newline
println(isInstanceOf<String>("Kotlin"))
// Print `isInstanceOf<Int>("Kotlin")` to the console, with a trailing newline
println(isInstanceOf<Int>("Kotlin"))
}
Login to try C/C++/Java/PHP code in the editor
Using T::class with Reified
A reified type parameter also allows accessing T::class directly, which is useful for logging, reflection-lite checks, or building generic factories.
Example: Using T::class with Reified
inline fun <reified T> typeName(): String = T::class.simpleName ?: "Unknown"
// Entry point: execution of the program starts here
fun main() {
// Print `typeName<String>()` to the console, with a trailing newline
println(typeName<String>())
// Print `typeName<Int>()` to the console, with a trailing newline
println(typeName<Int>())
}
Login to try C/C++/Java/PHP code in the editor
Filtering a List by Reified Type
A common practical use of reified generics is filtering a mixed collection down to only the elements of a specific runtime-checked type.
Example: Filtering a List by Reified Type
inline fun <reified T> filterByType(items: List<Any>): List<T> = items.filterIsInstance<T>()
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `mixed`, set to `listOf(1, "two", 3, "four", 5)`
val mixed = listOf(1, "two", 3, "four", 5)
// Declare a read-only variable `strings`, set to `filterByType<String>(mixed)`
val strings = filterByType<String>(mixed)
// Print `strings` to the console, with a trailing newline
println(strings)
}
Login to try C/C++/Java/PHP code in the editor
- Trying to use
T::classoris Tin a regular (non-inline) generic function, which fails to compile because the type is erased at runtime. - Forgetting that
reifiedcan only be used on a type parameter of aninlinefunction, since the type information is preserved by inlining, not by the JVM itself. - Overusing reified generics where a simple
Class<T>parameter passed explicitly would work just as well and keep the function non-inline.
- Marking a type parameter
reifiedon aninlinefunction lets the actual type be checked and used at runtime inside that function. reifiedis only allowed on inline functions, because inlining is what preserves the real type information at each call site.- Reified type parameters enable operations like
is TandT::classthat are normally impossible due to JVM type erasure. - A common use is a generic helper function that filters or checks a collection by a runtime-provided type.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: