An inline function asks the Kotlin compiler to substitute its body at each call site rather than generate a normal function call. For higher-order functions, the passed lambda can be substituted too, avoiding the usual anonymous-class and lambda-object overhead while keeping reusable code compact. section 10.2 section 10.2.1
Inlining a locking helper
Mark a small lambda-taking helper inline when it wraps a direct operation. At a call such as synchronized(lock) { action() }, the lock, try/finally logic, and lambda body are compiled into the caller, producing code comparable to a Java synchronized statement. Prefer withLock for this particular locking task. section 10.2.1
Listing 10.14 Defining an inline function
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
inline fun <T> synchronized(lock: Lock, action: () -> T): T { #1
lock.lock()
try {
return action()
}
finally {
lock.unlock()
}
}
fun main() {
val l = ReentrantLock()
synchronized(l) {
// ...
}
}
This helper shows the typical shape: a small inline function invokes its action directly inside lock and cleanup logic. section 10.2.1
Inlining is not a blanket performance switch. It is most useful for functions that take lambdas: Kotlin avoids both the call and normally created lambda machinery. Ordinary calls may already be optimized by the JVM, whereas copying a large inline body to many call sites increases bytecode size and can make stacktraces less clear. Keep inline functions small; move unrelated work into a regular function when needed. section 10.2.4
Lambda parameters impose important limits:
- A lambda can be inlined when the function invokes it directly or passes it to another inline function. section 10.2.2
- A lambda stored for later use needs an object representation and cannot be inlined; mark that parameter noinline when a function mixes inlineable and non-inlineable lambdas. section 10.2.2
- Inline functions work across modules and third-party libraries. Java can call most of them, but those calls remain ordinary function calls. section 10.2.2
Collection operations illustrate the practical benefit. filter and map are inline, so a lambda-based filter can compile roughly like an explicit loop without extra lambda classes or objects. A filter/map chain still creates an intermediate collection; sequences are lazy but retain lambdas in intermediate objects, so they are not automatically a better choice for small collections. section 10.2.3 section 10.2.3
Reified type checks
An inline function may mark a type parameter reified, making the actual type argument available in its substituted body. This enables checks such as value is T and supports filterIsInstance<String>(), which selects only String values from a mixed collection. Reified parameters can be used in checks, casts, reflection, Java Class access, and calls to other functions, but cannot create T instances or belong to classes or non-inline functions. section 11.2.2 section 11.2.5
Inlining also enables non-local returns from lambdas passed to inline functions. Use it to build efficient, focused higher-order abstractions—not merely to replace every ordinary function call. section 10.4 section 10.2.4



