Inline only when it serves a concrete purpose
Inlining substitutes a function body and eligible lambdas at call sites. It can reduce some function-object overhead and enables reified type parameters, but larger generated code can offset the benefit.
inline fun repeatAction(times: Int, action: (Int) -> Unit) {
require(times >= 0)
for (index in 0 until times) action(index)
}
inline fun later(crossinline action: () -> Unit): () -> Unit = { action() }
crossinline forbids a non-local return from a lambda that is invoked through another context. noinline leaves a parameter as an ordinary function value so it can be stored or passed where inlining is impossible. Neither keyword makes the callback asynchronous.
Public inline functions expose implementation details to callers' compiled code and have restrictions on access to non-public declarations. Treat changes to them as library API decisions.
Exercise
Invoke repeatAction to collect indexes zero through two. Add a second noinline callback and return it from a helper. Try a non-local return inside later and explain the compiler rejection.