Background:
In the JVM, there is no information about the generics parameters at runtime (type erasure). Kotlin introduced the mechanism of reified generic parameters for inline functions to allow access to information about type T during execution without workarounds like passing Class<T>. This is one of the most powerful features of the Kotlin language.
Problem:
It is required to write a function that accepts some value of type T (generic) and performs different actions depending on the parameter type, without explicitly passing java.lang.Class and without reflection on Java level. Classical type erasure does not allow knowing type T at runtime.
Solution:
In Kotlin, for inline functions, it is allowed to declare generic parameters with the reified modifier, which allows to "capture" type T within the function body, work with it like a regular type, do type-checks, and create instances through reflection.
Code example:
inline fun <reified T> isOfType(value: Any): Boolean { return value is T } isOfType<String>(123) // false isOfType<Int>(123) // true
Key features:
Can reified be used outside of inline functions?
No! Only inline functions (and inline lazy properties) can have a reified generic parameter. The reason is the substitution of code at the call site; only this way can you "substitute" a specific type instead of T.
Code example:
// Compilation error: fun <reified T> errorFun() { } // Correct version: inline fun <reified T> okFun() { }
Can you get Class<T> inside an inline reified function?
Yes! You can simply write T::class.java or T::class. This is very convenient for writing generic factories, parsers, and working with the reflection API.
Code example:
inline fun <reified T> printType() { println(T::class.java) } printType<String>() // class java.lang.String
Can instances of type T be created via constructor in a reified function?
Partially. You can use reflection, but directly new T() like in C++ or C# won't work:
inline fun <reified T : Any> makeInstance(): T? { return T::class.constructors.firstOrNull()?.call() }
But this approach requires T to have a no-argument constructor.
Function with reified calling a heavy reflection operation in the code:
inline fun <reified T> foo(): T? = T::class.constructors.firstOrNull()?.call()
Pros:
Cons:
Using reified for universal type-check or safeCast:
inline fun <reified T> safeCast(value: Any?): T? = value as? T
Pros:
Cons: