Inline Functions
Inline functions, non-local return, and the crossinline and noinline modifiers.
5 questions
JuniorTheoryCommonWhat does marking a function inline do, and what is a non-local return?
What does marking a function inline do, and what is a non-local return?
inline copies the function body and its lambda arguments into each call site, avoiding lambda-object allocation. Because the lambda is inlined, a bare return in it is non-local — it exits the enclosing function, not the lambda.
Common mistakes
- ✗Thinking
inlineis just a speed hint with no effect on return semantics - ✗Believing a bare
returnin a lambda always returns only from the lambda - ✗Inlining huge functions, which bloats every call site instead of helping
Follow-up questions
- →How do you return only from the lambda itself rather than the enclosing function?
- →When does
inlinegive no real benefit and just add code size?
MiddleDebuggingOccasionalWhy won't this inline job compile when its lambda runs inside a Runnable?
Why won't this inline job compile when its lambda runs inside a Runnable?
An inlined lambda may do a non-local return, which is illegal inside the nested Runnable. Mark the parameter crossinline job: () -> Unit to forbid that return, so the lambda may run inside the Runnable. Or drop inline from job.
Common mistakes
- ✗Assuming any inline lambda can be called from anywhere, including a nested object
- ✗Reaching for
noinlinewhen the lambda actually needscrossinline - ✗Blaming the Java SAM conversion instead of the non-local-return rule
Follow-up questions
- →How does
crossinlinediffer fromnoinlinefor a lambda parameter? - →Why is a non-local return illegal inside the
Runnablebody specifically?
MiddlePerformanceOccasionalWhat does inline actually save at runtime compared with a non-inlined lambda?
What does inline actually save at runtime compared with a non-inlined lambda?
A non-inlined lambda becomes a function object on the JVM: a capturing lambda allocates a fresh instance per call, a non-capturing one is reused, and every use goes through a virtual invoke. inline copies the body into the call site, so there is no object and no invoke. The win is real in a hot loop or a thin higher-order function, and negligible for a lambda called once.
Common mistakes
- ✗Thinking a non-capturing lambda allocates on every call, when it can be reused
- ✗Believing
inlineonly removes a stack frame while the lambda object is still created - ✗Inlining a large function called from many sites, where code size costs more than the saved object
Follow-up questions
- →Why does a capturing lambda allocate per call while a non-capturing one does not?
- →When does inlining a large function cost more than the allocation it removes?
MiddleTheoryOccasionalWhen do you need noinline, and how does it differ from crossinline?
When do you need noinline, and how does it differ from crossinline?
In an inline function every lambda parameter is inlined, so there is no function object to hand around. noinline opts one parameter out: it stays a real function object, so you can store it in a field, return it, or pass it to a non-inline function. crossinline keeps the lambda inlined but bans a non-local return, letting it be called from a nested context.
Common mistakes
- ✗Swapping the two — using
noinlinewhere a call from a nested object needscrossinline - ✗Thinking
noinlinedisables inlining of the whole function rather than of one parameter - ✗Believing an inlined lambda can be stored in a field or returned with no modifier at all
Follow-up questions
- →Why can a
noinlinelambda be stored in a field while a default inlined one cannot? - →What does an
inlinefunction whose every lambda isnoinlinestill gain, if anything?
MiddleDebuggingRareWhy does crossinline break the return in this inline function?
Why does crossinline break the return in this inline function?
crossinline forbids a non-local return from the lambda, but this code relies on one — the return exits someFun. With crossinline it would not compile. Remove crossinline: plain inline already inlines action and permits the non-local return.
Common mistakes
- ✗Reading
crossinlineas a harmless optimisation rather than a ban on non-local return - ✗Thinking the
returnonly exits the lambda, socrossinlinechanges nothing - ✗Adding
noinlineto fix it, which also disables inlining of the lambda
Follow-up questions
- →In what situation would you actually need
crossinlineon this parameter? - →What is the difference between
crossinlineandnoinline?