What is non local return? In what scenarios it is useful? Please give an example to explain.
It means exiting a function and ending up someplace else beside where the function was called. It's primarily used to refer to exceptions (i.e., try
, throw
, and catch
in Java and C++), but it can also mean mechanisms like setjmp/longjmp
in C.
Here's a good article on the use of non local returns in the context of ruby blocks.
Ruby’s blocks support non-local-return (some references), which means that a return from the block behaves identically to returning from the block’s original context.
It basically mean that you can call a block from a function, and the block has the ability to return from the original function.
To explain the matter here is some sample code to explain what non-local returns are.
object Scratch {
def foo: Int = {
val list = List(1, 2, 3, 4)
list.foreach { each =>
if(each > 2) {
return each // NLR
}
println(each)
}
return 5
}
def main(args : Array[String]) : Unit = {
val i = foo
println("i: " + i)
}
The code above is in Scala, but things would be essential the same for any other language that supports non-local returns such as Kotlin and most prominently Smalltalk and Ruby (I think also most functional programming languages as well such as List).
The point is here that the code above would write this output to the console:
1
2
i: 3
So it does not print 4 and 5 to the console as well and that is in this example the big difference to languages that do not support non-local returns from within closures.
In the code snippet above the return at line "NLR" returns out of the closure >>and<< out of the function that invoked the closure. This is the difference to a local return which would return out of the closure but execution would thereafter continue at the next line after the closure in the same method that invoked the closure. The non-local return is in that sense not a local return any more, but an "uber" local return. However, it is somehow called non-local return.
In languages without non-local returns such as Java or C# the code above would be rejected by the compiler. In Java a plain return from within a lambda (just a return without returning a value) has the same effect as a continue.
Non-local returns cost a bit extra CPU time (which to my knowledge is very little) but also result in allocation on the heap as closures with a non-local return cannot be allocated on the stack any more. This is because such a closure can be passed over to other functions (that might be in a different thread as well). So closures that support non-local returns consume a bit more heap space.
When a non-local return is done from the function the closure was passed over to, the thread of execution jumps out of that function as displayed in the sample code here is well. I think this is the reason why many functional programming language support non-local returns as passing functions over as a parameter to other functions is a common way of doing things in functional programming.
Why are non-local returns an issue? Because you want to be able to return out of a closure just the same way you do from a for loop or while loop or a plain function. If that is not possible for a closure, the entire code that was written with closures to begin with has to rewritten once some non-local return needs to be done with a for or while loop. In that case the expressiveness of closures would be lost.