Scala Supports Non-Local Returns

Stephen Haberman - 07 Jan 2010

Writing some Scala code today, I found myself using non-local returns without even thinking about it. After realizing what I had done, I dug a little deeper to see what was really going on.

Take this completely made up, nonsensical example:

    object Foo {
      def main(args: Array[String]) {
        foo(List(1, 2, 3))

      def foo(l: List[Int]): Int = {
        l.foreach { (i) =>
          return 5
        return 10

This code will print "1" and then exit.

Perhaps this is obvious, that the "return 5" applies to the "foo" method, so the values 2 and 3 in "l" will not have a chance to be printed.

However, think about what is going on under the covers--Scala is passing the foreach method an anonymous inner class with a "void apply(int i)" method. And inside of that "apply" method is the code between the "{ (i) => ... }".

So, how does code inside of the "apply" method cause its caller to perform an early exit, without the "foreach" even knowing about it?


Here is the decompiled version of "print":

    public int print(List l) {
      Object localObject = new Object();
      int exceptionResult1 = 0;
      try {
        l.foreach(new AbstractFunction1() {
          public static final long serialVersionUID = 0L;
          public final Nothing. apply(int i) {
            // here is the "return"--it puts "5" into an exception
            throw new NonLocalReturnException(
        return 10;
      } catch (NonLocalReturnException localNonLocalReturnException)  {
        if (localNonLocalReturnException.key() == localObject) {
          // get "5" back out of the exception
          return BoxesRunTime.unboxToInt(localNonLocalReturnException.value());
        throw localNonLocalReturnException;

I think the decompiler got a little confused with "nonLocalReturnKey", but you can see the basic idea is that any early return inside of a closure is converted into an exception that is then caught outside of the closure where a proper return call can be done.

I personally think this is handy, once you know what is going on. But from what I've picked up, any closures that make it into Java 7 will not support non-local returns and instead disallow the return keyword inside of closures. Which, I guess, at this point any Java closures are better than no closures at all.

comments powered by Disqus