skip to content

What does the `noinline` modifier do when applied to a lambda parameter of an `inline` function?

level: juniorimportance: must knowfreq 55%

answer

  1. Keeps one lambda as a real Function object
  2. Lets you store / return / pass-onward the lambda
  3. Only meaningful inside an inline function
  4. Other lambdas still get inlined
  5. Redundant + warned on non-inline functions

basics

~20 s

It tells Kotlin NOT to inline that one lambda. Instead the lambda stays a normal object you can store in a variable or pass to another function, while the other lambdas in the inline function are still inlined.

solid answer

~40 s

When you mark a function `inline`, the compiler copies the function body and each lambda argument's body directly into the call site, so no lambda object is allocated. But sometimes you need a lambda to remain a real `Function` object — e.g. to store it in a field, return it, or pass it to a non-inline function. Marking that specific parameter `noinline` opts it out of inlining: it becomes an ordinary `FunctionN` instance. Other lambda parameters of the same function are still inlined. `noinline` is only meaningful on a lambda/function-type parameter of an `inline` function; on a non-inline function every lambda is already a real object, so the keyword is redundant there and the compiler warns.

code

kotlin · 7 lines
kotlin
inline fun run2(first: () -> Unit, noinline second: () -> Unit): () -> Unit {
    first()        // body copied in, no object
    return second  // returned as an object
}

val later = run2({ println("now") }, { println("later") })
later()  // prints "later"

go deeper

for a junior

Knows noinline keeps a specific lambda as a normal object so it can be stored or passed on.

for a middle

Explains it's per-parameter, only meaningful inside inline, and how it coexists with inlined parameters.

for a senior

Connects it to the allocation/Function-object model and contrasts cleanly with crossinline and the inline cost model.

for a principal

Frames noinline as an API-design and codegen tradeoff lever and reasons about when an inline+noinline split beats a plain function.

## What `inline` does first When a function is declared `inline`, the Kotlin compiler does not generate a normal call. Instead it copies the function's body — and the body of each lambda you pass — straight into the call site. The benefit: passing a lambda to a non-inline function normally allocates a `Function` object (a class implementing `kotlin.Function0`, `Function1`, etc.); inlining removes that allocation and the virtual `invoke` call. ## The problem `noinline` solves Inlining a lambda means the lambda has **no object form** inside the function body — there is nothing to assign to a variable, store in a field, or pass to another (non-inline) function. If your inline function needs to treat one of its lambdas as a real value, that lambda cannot be inlined. `noinline` is the per-parameter opt-out. Marking a lambda parameter `noinline` keeps it as a concrete `FunctionN` object, so you can: - store it in a `val`/field or a collection - return it from the function - pass it onward to a function that is **not** inline Meanwhile, any **other** lambda parameters of the same inline function are still inlined as usual. ```kotlin inline fun transform( inlined: () -> Unit, // inlined into call site noinline stored: () -> Unit // kept as a real object ): () -> Unit { inlined() return stored // legal ONLY because `stored` is noinline } ``` ## Where it is allowed `noinline` only applies to a function-type (lambda) parameter of an `inline` function. On a regular (non-inline) function, every lambda is already a heap object, so `noinline` is redundant and the compiler emits a warning. It is unrelated to value parameters of other types. ## Relationship to `crossinline` Both modify a lambda parameter of an inline function but in opposite directions: `crossinline` keeps the lambda inlined while forbidding non-local returns; `noinline` un-inlines the lambda entirely. You reach for `noinline` when you need the lambda as a value; you reach for `crossinline` when you still inline it but call it from a nested context.

  • If a function is NOT marked inline, does `noinline` do anything?
    No. In a non-inline function all lambdas are already real objects, so `noinline` is redundant and the compiler warns about it.
  • Can you mix inlined and noinline lambda parameters in one function?
    Yes — that's the point. You mark only the lambdas you need as objects `noinline`; the rest stay inlined.

Inlining is photocopying the recipe steps into the page; noinline keeps that one step as a separate index card you can hand to someone else.

saying these in an interview costs you the question

  • Saying `noinline` makes the whole function not inline (it's per-parameter)
  • Claiming `noinline` works on regular functions usefully
  • Confusing `noinline` with `crossinline`
  • Thinking `noinline` forbids non-local returns (that's crossinline)

context