Explain precisely how the compiler implements a `reified` parameter at the bytecode level, and what consequences this has for binary compatibility and public library APIs.
answer
- Reified = inline + compile-time type substitution, no runtime method
- Body is copied into callers -> inline functions are ABI
- Java cannot call reified functions -> offer Class<T> overload
- @PublishedApi for internal symbols used in public inline bodies
- Inlining bloats bytecode; tune with noinline/crossinline
basics
~20 sThere is no real generic function at runtime. The compiler copies the function body into each call site and replaces T with the concrete type there. So the type info lives in the caller's bytecode, which affects inlining cost, binary compatibility, and what callers (e.g. Java) can use.
solid answer
~60 sA `reified` parameter exists only because the function is `inline`. The compiler does not emit a callable method whose `T` is reified; instead, at every call site it **inlines** the body and **substitutes** the concrete type argument for `T`, turning `value is T` into a concrete `instanceof`, `T::class` into a constant class reference, etc. Consequences: (1) the type information is baked into each *caller's* bytecode, so changing the body of a published inline reified function changes already-compiled callers only after they recompile — a binary-compatibility hazard for libraries; (2) inlining can bloat call-site bytecode and may force `@PublishedApi` for internal symbols the inlined body touches, since the body now runs in the caller's context; (3) **Java callers cannot call reified Kotlin functions** at all, because there is no real method with a usable signature — this is a real interop boundary; (4) IR/`@InlineOnly`-style behavior means no synthetic method is generated for some inline functions. For library authors this means treating inline reified functions as part of the ABI: their bodies are effectively copied into consumers, so evolve them carefully and keep referenced declarations at least `@PublishedApi internal`.
code
kotlin · 7 lines// Library pattern: reified ergonomics + Java/reflective fallback + ABI hygiene
@PublishedApi
internal fun <T : Any> parseImpl(json: String, type: Class<T>): T = TODO()
fun <T : Any> parse(json: String, type: Class<T>): T = parseImpl(json, type) // Java-callable
inline fun <reified T : Any> parse(json: String): T = parseImpl(json, T::class.java) // Kotlingo deeper
Understands at a high level that the body is copied to the call site with the real type substituted.
Explains the inlining + substitution mechanism and that Java can't call reified functions.
Adds bytecode-bloat and reflective-handle consequences and the Class<T> overload pattern.
Treats inline reified functions as ABI: reasons about binary compatibility, @PublishedApi, body churn, and interop/versioning strategy for libraries.
## No runtime generic function exists The critical mental model: a `reified` type parameter is a **compile-time** device riding on `inline`. The compiler never produces a normal method where `T` is somehow "known at runtime." Instead, at each call site it performs two steps: 1. **Inline** the function body into the caller. 2. **Substitute** the concrete type argument for every use of `T`. ```kotlin inline fun <reified T> isT(x: Any) = x is T fun caller(a: Any) = isT<String>(a) ``` The compiled `caller` contains, conceptually, `a instanceof String` — the `String` is a literal in the caller's bytecode, not a parameter threaded at runtime. ## Consequence 1 — body is part of the ABI Because the body is copied into consumers, a published inline reified function's **implementation** leaks into callers' compiled code. If you change the body in v2 of a library, code compiled against v1 keeps the **old** inlined body until it is recompiled. So inline functions (reified or not) are an ABI surface — evolve them conservatively. Anything they reference must be visible to callers; the `@PublishedApi` annotation lets an `internal` declaration be used from a public inline body without exposing it normally. ## Consequence 2 — Java interop boundary Java has no notion of Kotlin inlining or reification. There is no ordinary method to bind to, so **Java code cannot call a reified function**. If you need Java interop, expose a `Class<T>`-parameter overload: ```kotlin fun <T : Any> parse(json: String, type: Class<T>): T = ... // Java-callable inline fun <reified T : Any> parse(json: String): T = parse(json, T::class.java) // Kotlin ergonomic ``` ## Consequence 3 — bytecode size & hotspots Every call site gets a copy of the body. For small bodies this is fine and often faster (no megamorphic dispatch, JIT-friendly). For large bodies called in many places it bloats class files and can hurt instruction-cache behavior. Use `noinline`/`crossinline` on lambda parameters to control what gets inlined, and consider a non-inline core with a thin reified wrapper. ## Consequence 4 — no reflective handle Since the reified function isn't a standalone method, you can't get a `KFunction`/reflect over it the same way, and you can't recursively pass `T` to another reified call via a plain (non-reified) type variable. ## Practical guidance for library authors - Treat inline reified functions as **stable ABI**; minimize body churn. - Mark internal helpers used by public inline bodies `@PublishedApi internal`. - Provide `Class<T>`/`KClass<T>` overloads for Java and reflective callers. - Use reified for ergonomic *call-site* type capture (serialization, DI, logging tags), not as a substitute for runtime type modeling.
- Why is changing the body of a published inline reified function a binary-compatibility concern?Because the body is inlined into every consumer at their compile time. Existing compiled consumers keep the old body until recompiled, so behavior can diverge across versions and you can't hot-swap the implementation by shipping a new jar alone.
- What is `@PublishedApi` for in this context?It lets an `internal` declaration be referenced from a public `inline` function body. Since that body is copied into external callers, anything it touches must be accessible to them; `@PublishedApi internal` grants that access without making the symbol part of the normal public API.
saying these in an interview costs you the question
- Believing a reified function is a normal method that reads runtime type metadata
- Saying Java can call reified Kotlin functions
- Ignoring that inline bodies are part of the ABI
- Not knowing @PublishedApi is needed for internal symbols in public inline bodies
- Claiming reification has zero bytecode-size impact