Kotlin inline Keyword
last modified April 19, 2025
Kotlin's inline
keyword is used to optimize higher-order functions.
It eliminates the overhead of function calls by inlining the function body. This
tutorial explores the inline
keyword in depth with practical examples.
Basic Definitions
The inline
keyword tells the compiler to copy the function's bytecode
where it's called. This avoids the runtime overhead of function objects. It's
most beneficial for higher-order functions that take lambdas as parameters.
Basic Inline Function
A simple inline function demonstrates how the compiler replaces calls with the function body. This can improve performance for small, frequently called functions.
package com.zetcode inline fun greet(name: String, action: (String) -> Unit) { println("Hello, $name!") action(name) } fun main() { greet("Kotlin") { name -> println("$name is awesome!") } }
The greet
function is marked as inline. When called, its body is
copied directly into the calling code. The lambda parameter is also inlined,
avoiding the creation of a function object.
Performance Comparison
This example compares the performance of inline vs non-inline functions. The difference is most noticeable with small, frequently called functions.
package com.zetcode inline fun inlineOperation(a: Int, b: Int, op: (Int, Int) -> Int): Int { return op(a, b) } fun normalOperation(a: Int, b: Int, op: (Int, Int) -> Int): Int { return op(a, b) } fun main() { val iterations = 1_000_000 val inlineTime = measureTimeMillis { repeat(iterations) { inlineOperation(5, 3) { x, y -> x + y } } } val normalTime = measureTimeMillis { repeat(iterations) { normalOperation(5, 3) { x, y -> x + y } } } println("Inline time: $inlineTime ms") println("Normal time: $normalTime ms") }
The inline version typically shows better performance for many iterations. This is because it avoids creating function objects for each lambda call. The difference becomes more significant with frequent calls.
Reified Type Parameters
Inline functions enable reified type parameters, which preserve type information at runtime. This allows type checks and casts that aren't possible with regular generics.
package com.zetcode inline fun <reified T> checkType(obj: Any) { if (obj is T) { println("Object is of type ${T::class.simpleName}") } else { println("Object is NOT of type ${T::class.simpleName}") } } fun main() { checkType<String>("Kotlin") // Output: Object is of type String checkType<Int>("123") // Output: Object is NOT of type Int }
The reified
keyword allows accessing the actual type parameter at
runtime. This is impossible with regular generics due to type erasure. The
function can perform runtime type checks on the generic type.
Inline Properties
The inline
modifier can also be applied to property accessors. This
works similarly to inline functions, optimizing property access.
package com.zetcode class User(val name: String) { var lastAccess: Long = 0 inline get() { println("Getting last access time") return field } inline set(value) { println("Setting last access time") field = value } } fun main() { val user = User("Alice") user.lastAccess = System.currentTimeMillis() println(user.lastAccess) }
Both getter and setter for lastAccess
are marked as inline. The
compiler will inline these accessors at call sites. This is useful for simple
property accessors with logging or validation.
Crossinline and Noinline
crossinline
and noinline
modify inline behavior.
crossinline
ensures lambdas can't use non-local returns, while
noinline
prevents inlining of specific parameters.
package com.zetcode inline fun execute( crossinline task: () -> Unit, noinline callback: () -> Unit ) { task() runLater(callback) } fun runLater(action: () -> Unit) { // Simulate async execution Thread.sleep(100) action() } fun main() { execute( { println("Task executed") }, { println("Callback executed") } ) }
The task
parameter uses crossinline
to prevent
non-local returns. The callback
uses noinline
because
it's passed to another function. These modifiers provide control over inlining.
Inline Functions in Collections
Kotlin's standard library uses inline functions extensively for collection operations. This example demonstrates how they work internally.
package com.zetcode fun main() { val numbers = listOf(1, 2, 3, 4, 5) val squares = numbers.map { it * it } println(squares) // [1, 4, 9, 16, 25] val evens = numbers.filter { it % 2 == 0 } println(evens) // [2, 4] val sum = numbers.fold(0) { acc, num -> acc + num } println(sum) // 15 }
Functions like map
, filter
, and fold
are
inline in Kotlin's standard library. This makes collection operations efficient
despite using lambdas. The compiler inlines both the function and lambda bodies.
When Not to Use Inline
This example shows cases where inline functions might not be beneficial or could even harm performance.
package com.zetcode // Not good for large functions inline fun largeInlineFunction() { // Hundreds of lines of code... println("This function is too large to benefit from inlining") } // Recursive functions can't be inlined inline fun recursiveFunction(n: Int) { if (n > 0) { println(n) recursiveFunction(n - 1) // Error: recursive inline function } } fun main() { largeInlineFunction() }
Inline functions increase code size when the function body is large. Recursive functions can't be inlined. Also, public API functions might need careful consideration before inlining due to binary compatibility.
Best Practices for Inline Functions
- Use for small functions: Ideal for functions with few lines that are called frequently.
- Higher-order functions: Best for functions accepting lambdas to avoid function object overhead.
- Reified types: Essential when you need runtime type information for generic parameters.
- Avoid large functions: Inlining large functions increases bytecode size without significant benefits.
- Consider noinline: Use when some lambdas need to be stored or passed to non-inline functions.
Source
Kotlin Inline Functions Documentation
This tutorial covered Kotlin's inline
keyword in depth, showing its
benefits for performance and reified types. We explored various scenarios
including collections, properties, and parameter modifiers. Proper use of inline
functions can make your Kotlin code more efficient while maintaining clarity.
Author
List all Kotlin tutorials.