Confusion about whether non-local returns work or not

Hello,

some time ago I read in the documentation about inline functions in the section named “Non-local returns”. I somehow got the impression that those NLR only work in certain cases where the closure can be inlined.

Then I found this code snippet by Andrey Breslav showing some workaround how to do a NLR with wrapping a try-catch block around the lambda. So this then gave to me the impression that you can’t do a NLR in a foreach.

Today I hacked in this code an the NLR there just worked:

fun bar() : Int {
    val list = listOf(1, 2, 3, 4)
    list.forEach {
        if(it >= 2) {
            return it
        }
        println(it)
    }
    println("must not get here")
    return -1
}

fun main(args: Array<String>) {
    val num = bar()
    println(num)
}

The code above compiles and prints correctly to the console:

1
2

So the NLR just worked without any further ado like inline and whatever. And now I’m quite confused when NLR work and when they don’t. The issue in “Non-local returns” only concerns nested lambdas? Other than that NLR are working? If I can rely on them working from within collection iterators (foreach, map, filter, etc.) I’m actually happy enough.

Okay, I’m getting it now: forEach in CollectionsKt is declared with the inline keyword. If I write my own forEach I need to make sure I also declare with inline and things are fine.

I would suggest that the section about NLR shows some sample where you can see a NLR being done from within a forEach, map, filter or whatever. I think this is very important information for people being interested in Kotlin that NLR do work there. At least to me it wasn’t clear at all and misleading and other people might decide not to look any further into Kotlin because they also misunderstand this.

Always thinking they don’t work in Kotlin made me repeatedly think of still using Scala, because if I can’t do a NLR from within a forEach I either change to Scala or just stick to crappy Java streams that also can’t do NLR.

Maybe you remove this Gist https://gist.github.com/abreslav/6916859 or add a comment to it that it no longer applies. Because it can be googled with “Kotlin non-local return” and then gives the impression that it cannot be done in Kotlin.

In the text snippet above in the red box maybe add a remark that forEach was declared with inline for this to work. Then it is much clearer :slight_smile:

1 Like

I think that the “inline functions often enclose” words right before the example, along with the name of the topic in which this example is found, explain sufficiently clearly that we’re talking about an inline function.

And if people use random 4-year-old gists floating around on the Internet with no context as a source of information, then yes, they can get incorrect impressions about all sorts of things.

1 Like

Well, then that’s how it may be. For me seeing NLR working from within collection iterators gave me the missing link. Now it’s clear to me that Kotlin with its feature set and clean approach towards language design is the best OO language on the JVM and sooner or later will be the clear number 2 in usage count after Java.

Sorry popping out of blue after a while. I ran into this post when I was trying to clarify why non-local returns are forbidden for real.

I see some comments on web comments related to JVM being technically incapable of having non-local returns inside lambdas. And that’s pretty much it :). I wasn’t able to find any proper reasoning around it. For instance, is this the compiler which is not able to figure out from where to return when a non-local return is used inside a lambda? Is it too hard to compile such a code? The last expression of a lambda is already returned implicitly to the point where lambda gets called as similar as labeled returns. So, it feels like it’s technical but not entirely…

I’ve seen in a Kotlin book that says it’s also semantically not right to use a non-local return from a lambda as it may cause premature exit before the returned value (a function maybe) is executed – in other words, too late to take any effect!

If I combine the above two paragraphs, it makes more sense but still not sure if I still one the right path or not. So, I am a bit confused here and I hope I’ve been clear. Can you please give me some help on this?

I see some comments on web comments related to JVM being technically incapable of having non-local returns inside lambdas

That is correct. The trick to get it accomplished in spite of those limitations o the JVM in Kotlin is through inlining the closure, see https://kotlinlang.org/docs/reference/inline-functions.html