Safe non-local returns using crossinline for inline functions in kotlin
A higher-order function is a function that either takes another function as a parameter, returns a function, or both. These functions are a key feature of Kotlin and provide much flexibility when writing functional-style code.
In some cases, when using a lambda expression as an argument for a higher-order function, we might use the return keyword inside the lambda to exit the function early. This scenario is known as a non-local return because the return statement not only exits the lambda but an interesting scenario arises when a non-local return coincides with a function marked with the inline marker.
Example of a Non-Local Return
fun doSomething(operation: () -> Unit){
operation()
}
fun main() {
doSomething(
operation = {
// do something
return // this exits the lambda
}
)
}
Note: A return typically exits the execution of the enclosing function.
Inline functions
In Kotlin, we often make use of inline functions. Declaring a function as inline instructs the compiler to copy the function’s body to the call site during compilation. This is especially useful for performance when dealing with higher-order functions, as it reduces the overhead of lambda allocations.
Example of an inline function
inline fun doSomething(operation: () -> Unit) {
operation()
}
The issue with non-local returns and inline functions
When you have a non-local return in an inline function, the return statement will also apply to the function that calls the inline function. For example, in the code above, the return statement inside the lambda will cause the main() function to exit early, leading to unpredictable behavior.
To prevent this, Kotlin offers a solution: the crossinline keyword.
Using crossinline to prevent non-local returns
The crossinline keyword is used in the parameter list of an inline function to prohibit non-local returns. This ensures that the lambda passed to the higher-order function cannot return to its caller.
inline fun doSomething(crossinline operation: () -> Unit) {
operation()
}
By using crossinline, you ensure that any return statement inside the lambda can only exit the lambda itself, making your code more deterministic and easier to debug.
Using higher-order functions, inline functions, and the crossinline keyword allows Kotlin developers to write efficient, performant, and predictable code. By avoiding non-local returns when necessary, you can make sure that your code is easier to maintain and understand by your team.
And that’s it for today. Happy coding!
Tschüss! 🤓