Kotlin inline, noinline and crossline
๐ What is an inline function in Kotlin? When we should use it and when not ?
1. Higher-Order Functions with Lambdas
This is the primary reason for inline. If your function accepts a lambda, inlining can prevent the overhead of creating an anonymous class for that lambda.
inline fun<T> measureTime(block: () -> T): T {
val start = System.currentTimeMillis()
val result = block()
println("Elapsed time: ${System.currentTimeMillis() - start}ms")
return result
}
2. Using reified Type Parameters
In Kotlin/JVM, type information is erased at runtime. If you need to check a generic type (e.g., T is String), you must use an inline function with a reified parameter.
inline fun <reified T> List<Any>.filterIsInstance(): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (item is T) result.add(item)
}
return result
}
3. Non-Local Returns
Inside a lambda passed to an inline function, you can use a naked return to exit the calling function. In a regular (non-inline) lambda, you can only return from the lambda itself using a label.
๐ When to Avoid inline
-
Large Functions: If the function body is large, inlining it everywhere it’s called will significantly increase your binary size (code bloat). Keep inlined functions small.
-
No Lambda Parameters: If your function doesn't take a lambda, there is virtually no performance benefit to inlining it. The compiler generally handles standard function optimization better than manual inlining.
-
Recursive Functions: Inlining a function that calls itself is impossible for the compiler to resolve at compile-time.
๐ What is an noinline andcrosslinein Kotlin? When we should use it?
inline, every lambda parameter passed to it is also inlined by default. However, there are times when you need to "opt-out" of this behavior for specific lambdas. That’s where noinline and crossinline come in.1. noinline
By default, all lambdas in an inline function are inlined. Use noinline when you want a specific lambda to behave like a regular object.
The Problem
Inlined lambdas can only be called inside the function. You cannot store them in a variable, pass them to another non-inline function, or return them.
The Usecase
-
Storage: If you need to save the lambda to a property or a list.
-
Passing around: If you need to pass the lambda as an argument to another function that is not inlined.
inline fun doSomething(
inlinedLambda: () -> Unit,
noinline persistentLambda: () -> Unit // This remains an object
) {
inlinedLambda() // Code is copied here
// We can pass persistentLambda to another function because it's an object
anotherFunction(persistentLambda)
}
2. crossinline
crossinline is used when you want the performance benefits of inlining, but you need to prevent the caller from using a non-local return.
The Problem
Standard inline lambdas allow the caller to use return to exit the outer function. However, if the inline function executes the lambda inside another execution context (like a nested lambda, a local object, or a callback), a non-local return would be "illegal" because the return would happen in a different scope than expected.
The Usecase
-
Nested Scopes: When you call the lambda inside another object (like a
Runnableor aTimerTask). -
Callbacks: When the lambda is used inside a higher-order function that is called later.
inline fun runDelayed(crossinline block: () -> Unit) {
val runnable = Runnable {
block() // 'block' is called inside a nested context
}
// Logic to run runnable...
}
// Call site
fun test() {
runDelayed {
// return // ERROR: 'return' is not allowed here because of crossinline
}
}
| Modifier | Can be stored/passed? | Can use "return" (non-local)? | Performance |
| Standard Inline | No | Yes | Highest (Full inlining) |
noinline | Yes | No | Normal (Object creation) |
crossinline | No | No | High (Inlined, but restricted) |
When to use what?
-
Use
inlineby default for higher-order functions to save memory. -
Add
noinlineif you get a compiler error saying you can't store the lambda. -
Add
crossinlineif you get a compiler error saying "can't inline because it's called in another context."
Comments
Post a Comment