What is a `reified` type parameter in Kotlin, and why does it require the function to be `inline`?
answer
- JVM erases generics; reified retains the type
- reified requires inline
- Unlocks is T, as? T, T::class, typeOf<T>()
- Compiler substitutes the real type at each call site
- filterIsInstance<T>() is the poster child
basics
~20 sreified lets a generic function know its actual type at runtime. Normally that type is erased and forgotten. It only works on inline functions because the compiler copies the code in and fills in the real type.
solid answer
~40 sOn the JVM, generic type arguments are erased at compile time, so a plain `fun <T> foo()` cannot do `is T`, `T::class`, or `T::class.java`. Marking the parameter `reified` (only allowed on `inline fun`) makes the compiler substitute the concrete type at every call site when it inlines the body. Because the real type is now baked into the generated bytecode, runtime checks like `is T`, `as? T`, `T::class`, and `typeOf<T>()` compile and work. The classic enabler is `inline fun <reified T> Iterable<*>.filterIsInstance()`. The cost: the body is duplicated at each call site, and a `reified` function can't be called reflectively or from non-inline contexts where T is unknown.
code
kotlin · 4 linesinline fun <reified T> Any?.cast(): T? = this as? T
val s: String? = (42 as Any?).cast<String>() // null, no crash
val n: Int? = (42 as Any?).cast<Int>() // 42go deeper
Knows reified gives the runtime type and must pair with inline; can recall filterIsInstance.
Explains erasure clearly and lists the concrete capabilities (is/as/T::class/typeOf) plus the call-site substitution mechanism.
Articulates the codegen (body copied, type substituted), the inability to forward a non-reified T, and code-size tradeoffs.
Reasons about API design: when to expose reified overloads vs KClass parameters, reflection/interop limits, and binary-compatibility implications of inlined reified bodies.
## The problem: type erasure The JVM uses **type erasure** — generic type arguments exist only at compile time and are stripped from the bytecode. At runtime a `List<String>` and a `List<Int>` are both just `List`. So inside a plain generic function you cannot ask questions about `T`: ```kotlin fun <T> isInstance(value: Any): Boolean = value is T // ERROR: Cannot check for instance of erased type: T ``` The compiler rejects `value is T` and `T::class` because, after erasure, there is no `T` to check against. ## The fix: `reified` on an `inline` function Marking a type parameter `reified` tells the compiler to **retain** the concrete type argument. This is only legal on an `inline fun`: ```kotlin inline fun <reified T> isInstance(value: Any): Boolean = value is T ``` **How it works:** an `inline` function's body is copied into the call site at compile time. At that call site the real type argument is known, so the compiler substitutes the actual class for `T`. The generated bytecode at the call site looks like `value is String` (no `T` at all), so there is nothing left to erase. ```kotlin val r = isInstance<String>("hi") // compiler emits: "hi" is String ``` ## What `reified` unlocks With `reified T` you can use, inside the function body: - `value is T` and `value !is T` — type checks - `value as T` and `value as? T` — casts - `T::class` (a `KClass<T>`) and `T::class.java` (a `Class<T>`) - `typeOf<T>()` — a full `KType` including nullability and nested generics ## Standard-library examples ```kotlin public inline fun <reified R> Iterable<*>.filterIsInstance(): List<R> = ... ``` `filterIsInstance<String>()` keeps only `String` elements — impossible without `reified`. Many serialization/JSON libraries expose `inline fun <reified T> decode(json: String): T` for the same reason. ## Costs and limits - Inlining **duplicates** the body at every call site (code-size cost). - A `reified` parameter must be a **concrete** type at the call site; you cannot forward a non-reified `T` from an outer non-inline function into a `reified` slot. - `reified` functions cannot be called via reflection and are effectively not part of a usable virtual dispatch surface (they're inlined).
- Why can't you mark a `reified` parameter on a normal (non-inline) function?Without inlining there is no call site to substitute the concrete type into, so the type would still be erased at runtime; the compiler has nowhere to bake in the real class.
- Does `reified` defeat JVM type erasure globally?No. Erasure still happens. `reified` just substitutes the concrete type at each inline call site, so within that copied body the type is known. The general type system is unchanged.
Erasure is like mailing a sealed box with no label; reified writes the contents on the outside before sealing, so the receiver knows what's inside.
saying these in an interview costs you the question
- Claiming reified works on any generic function, not just inline ones
- Saying reified 'turns off' or 'removes' JVM type erasure
- Not knowing is T / T::class fail on a plain generic parameter
- Confusing reified with @JvmStatic or annotations
- Thinking reified has zero cost (ignoring code duplication)