Skip to content

Instantly share code, notes, and snippets.

@kriskowal
Created January 28, 2012 00:28
Show Gist options
  • Save kriskowal/1691779 to your computer and use it in GitHub Desktop.
Save kriskowal/1691779 to your computer and use it in GitHub Desktop.
function foo() {
bar({|x|
return 10;
});
}
function bar(block) {
block();
block(); // we should never get here. how?
}
foo();
10 foo(); // stack: []
2 bar({|x| return 10}) // stack: [foo]
7 block() // stack: [foo, bar]
3 return 10 // stack: [foo, bar, block]
@kriskowal
Copy link
Author

@dherman Right. The finally clause might be enough.

I did not mean to imply that you could fabricate a ReturnValue exception and throw it, causing a return from the first parent scope. I mean that a return in a block lambda would construct a ReturnValue exception with a read-only value (at least), add it to a side-table.

var sideTable = new WeakMap();

// return value desugars
var exception = new ReturnValue(value);
sideTable.set(exception, foo);
throw exception;

// foo desugars
function foo() {
    try {
    } catch (x) {
        if (sideTable.get(x) === foo) {
            return x.value;
        } else {
            throw x;
        }
    }
}

Then foo would implicitly catch the exception and convert a ReturnValue.value into a return value only if the exception in the side-table maps to foo.

This would make it possible for an intermediary to observe the exception in a catch block, rethrow it, or throw a different exception. It would not give the ability to return an arbitrary value from an arbitrary parent scope.

@kriskowal
Copy link
Author

@dherman I think that finally will have to suffice. It would be an information/capability leak for an intermediate stack frame to be able to observe the return value in a parent lexical scope. MarkM would kill me for suggesting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment