Why does an explicit return statement (one that uses the return
keyword) in an anonymous function return from the enclosing named function, and not just from the anonymous function itself?
E.g. the following program results in a type error:
def foo: String = {
((x: Integer) => return x)
"foo"
}
I know it's recommended to avoid the return
keyword, but I'm interested in why the explicit and implicit return statements have a different semantics in anonymous functions.
In the following example, the return statement "survives" after m
has finished executing, and the program results in a run-time exception. If anonymous functions didn't return from the enclosing function, it would not be possible to compile that code.
def main(args: Array[String]) {
m(3)
}
def m: (Integer => Unit) =
(x: Integer) => return (y: Integer) => 2
The
return
keyword is reserved for (class) methods, it cannot be used in functions. You can easily test that:This gives
Mostly you can treat methods and functions as the same, because of the function's
apply
method behaving syntactically like calling a method, and so-called eta-expansion allowing a method to be passed as a function argument.In this case, it makes a difference. When defining as method, it is legal:
In summary, you should only use
return
in methods that allow conditional (early) returns. See this post for a discussion on methods versus functions.Formally speaking return is defined as always returning from the nearest enclosing named method
So it doesn't have different semantics in a lambda. The wrinkle is that, unlike a normal method, a closure created from a lambda can escape a call to the enclosing method and you can get an exception if there is a return in such a closure.
Now, as for "why". One lesser reason is aesthetic: lambdas are expressions and it's nice when an expression and all its subexpression have the same meaning no matter what the nesting structure. Neal Gafter talks about that at http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
The main reason it exists, though, is it allows you to easily simulate forms of control flow commonly used in imperative programming but still allows you to abstract things into higher order functions. As a toy example, Java's foreach construct (
for (x : xs) { yada; }
) allows a return inside the loop. Scala doesn't have a language level foreach. Instead, it puts foreach in the library (not counting "for expression" without yield since they just desugar to foreach). Having a non-local return means you can take a Java foreach and translate directly to a Scala foreach.BTW, Ruby, Smalltalk, and Common Lisp (off the top of my head) also have similar "non-local" returns.