Return from Kotlin’s lambda

Roman Bielokon
Jul 29, 2018 · 2 min read

Working with Kotlin I found that “return” from lambdas is not always obvious and sometimes may lead to the issues. So let’s try to demystify “returns” with the examples.

First, let’s consider a function that receives a lambda as a parameter and call it inside(BTW this function in Kotlin is called High-Order function — HOF):

fun testWithAction(action:() -> Int) {
println("start test")
val result = action()
println("end test with $result")
}

Because testWithAction is a HOF, We can write lambda outside the parentheses and also We can omit the parentheses because they are empty. So the call for this function may look like this:

testWithAction {
println("Some action")
...
}

And now We want to return a result from this lambda:

testWithAction {
println("Some action")
return 42
}

What We actually received— compile error: ‘return’ is not allowed here. So what to do? There are at least two ways how to return a value from a lambda. The first one is to write the result as the last expression in the lambda without any ‘return’:

testWithAction {
println("Some action")
42
}

The second possible way is to use so-called “qualified return syntax”:

testWithAction {
...
return@testWithAction 42
}

We used the name of the function as a label. But also We can specify our own label:

testWithAction marker@{
...
return@marker 42
}

Let’s go further and “inline” testWithAction:

inline fun testInline(action:() -> Int) {
println("start testInline")
val result = action()
println("end testInline with $result")
}

In this case We can call “return” inside the action():

fun someFunction() {
println("start someFunction")
testInline {
println("do some action")
return
}
println("end someFunction")
}

Seems everything is cool and obvious, but wait… Let’s take a look at the output:

start someFunction
start testInline
do some action

Hmmm, something went wrong… Everything after “return” was not performed.

Indeed, because HOF is inlined, all “return” statements inside it will actually return from the function someFunction.

The rule for the inlined lambdas is next: “return” statement will return from the nearest enclosing function(in other words — will return from the nearest fun). This can lead to the unpredictable behavior and to the issues.

And now You can ask me how to avoid misuse of such a function when You provide some inline functions to the other developers. And the solution is to use crossinline:

inline fun testCrossinline(crossinline action:() -> Unit) {
println("start testCrossinline")
action()
println("end testCrossinline")
}

After We mark a lambda-param as crossinline the user of such a HOF will not be able to call “return” in lambdas. The same rules are applied as for non-inline HOF: You can write “return” only with a label or the last expression in a lambda will be a return value for it.


I hope this article was useful for You. Looking forward to Your feedback and feel free to ask any questions.

P.S. Don’t forget to clap and share this article with other Kotlin fans

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade