What does the `inline` modifier do to a Kotlin function, and why is it most useful on functions that take lambda parameters?
answer
- Copies body into call site
- No FunctionN allocation, no invoke() dispatch
- Powers let/run/with/apply/also
- Best with lambda params
- Cost = bigger bytecode
basics
~20 sinline tells the compiler to copy the function's body straight into each place it is called, instead of making a real function call. This avoids creating an object for the lambda you pass in, so it runs faster.
solid answer
~40 sMarking a function `inline` makes the compiler substitute the function body at every call site rather than emitting an actual JVM method invocation. The big win is for higher-order functions: normally a lambda passed as an argument is compiled to a `FunctionN` object (e.g. `Function1`) that gets allocated and invoked virtually. When the function is `inline`, both the function body and the lambda body are copied into the caller, so no `FunctionN` instance is created and there is no extra call indirection. That is exactly how the stdlib scope functions `let`, `run`, `with`, `apply`, and `also` and collection ops like `forEach`/`map` stay zero-overhead. The trade-off is larger bytecode at each call site, so `inline` pays off when there are lambda params, not on ordinary functions.
code
kotlin · 8 linesinline fun <T> T.alsoLog(tag: String, block: (T) -> Unit): T {
println("$tag: $this")
block(this)
return this
}
// At the call site no Function1 object is created for { ... }
val n = 42.alsoLog("value") { println(it * 2) }go deeper
Can state that inline copies the body into the call site and avoids creating a lambda object.
Names FunctionN allocation and invoke() dispatch as the concrete costs removed, and cites the scope functions as examples.
Frames it as the enabler of zero-overhead HOFs and notes the bytecode-size trade-off and the no-functional-param warning.
Reasons about when inlining is a net win across a codebase (hot small HOFs vs. code-size blowup) and how it interacts with JIT and other inline-only features.
## What `inline` means The `inline` keyword is a modifier on a function. It instructs the Kotlin compiler to perform **inlining**: instead of generating a normal method call, the compiler **copies the function's compiled body directly into every call site**. A **call site** is any place in your code where the function is invoked. A **higher-order function (HOF)** is a function that takes another function (a lambda) as a parameter or returns one. ## Why lambdas normally cost an allocation When you pass a lambda to a regular (non-inline) function, the Kotlin compiler turns that lambda into an **object** implementing a `FunctionN` interface — `Function0`, `Function1`, … depending on the number of arguments. Calling the lambda is a **virtual call** through `invoke()`. So a plain HOF involves: - allocating a `FunctionN` object (heap pressure, potential GC), - a virtual `invoke()` dispatch each time the lambda runs. ## What inlining removes With `inline`, the compiler copies **both** the function body **and** the lambda body into the caller. Result: - **No `FunctionN` object** is allocated for the lambda. - **No `invoke()` indirection** — the lambda's statements sit inline in the caller. ```kotlin inline fun measure(block: () -> Unit) { val start = System.nanoTime() block() println("took ${System.nanoTime() - start} ns") } fun work() { measure { println("hello") } } ``` After inlining, `work()` is compiled roughly as if you had written the timing code and `println("hello")` directly inside `work` — no lambda object, no extra method. ## Where you already rely on this The standard library **scope functions** `let`, `run`, `with`, `apply`, `also` are all `inline`, as are `repeat`, `forEach`, `map`, `filter`, `takeIf`, `synchronized`, and `runCatching`. That is why using them in hot loops carries essentially no overhead versus hand-written code. ## The cost Inlining duplicates bytecode at each call site, so a large `inline` function called in many places **increases code size**. The feature is intended for **small functions with lambda parameters**; the compiler even warns ("expected performance impact is insignificant") if you mark an `inline` function that has no functional parameters.
- Does `inline` change the observable behavior of the function?No — it is purely a codegen optimization. Same results; only the generated bytecode and performance characteristics differ (plus it enables non-local returns and `reified`, which are separate features).
- Is it worth marking a function with no lambda parameters `inline`?Usually not; the JIT already optimizes ordinary calls. The compiler warns it has insignificant benefit. You'd only do it to enable `reified` type parameters.
Like copy-pasting a snippet everywhere you'd call it, instead of phoning a shared helper each time.
saying these in an interview costs you the question
- Saying inline makes the function run on a separate thread or is async
- Claiming inline always makes code faster regardless of size
- Confusing `inline` with `inline class` / `value class`
- Thinking it inlines the call but still allocates the lambda object
- Believing it changes the function's results, not just its codegen