Interview frequency: …
Short answer
inline merges the function's code and its lambda at the call site; noinline prevents inlining of a specific lambda; crossinline allows inlining while forbidding non-local returns.
Explanation
inline removes the overhead of allocating objects for lambdas and replaces the call with direct code. If the function takes more than one lambda and we want to pass one of them as an ordinary object, we use noinline. crossinline is used when the lambda is invoked inside another scope (such as a Runnable or a coroutine), preventing the lambda from performing a non-local return that would end the original function.
Code example
val callbacks = mutableListOf<() -> Unit>()
inline fun performWork(
crossinline onAsyncCallback: () -> Unit,
noinline normalCallback: () -> Unit,
) {
// The lambda runs inside another object/context (a Runnable), so it must be crossinline:
// a non-local `return` from it would be illegal there.
val task = Runnable { onAsyncCallback() }
Thread(task).start()
// The lambda is stored as an object, which an inlined lambda cannot be → noinline
callbacks += normalCallback
}Common mistakes
- Making large functions inline, which leads to bytecode bloat.
- Trying to use inline on regular functions that take no lambda parameters, gaining no benefit from inlining.