block-lambda revival

Lasse Reichstein reichsteinatwork at
Mon Jun 27 04:49:47 PDT 2011

On Sat, 25 Jun 2011 05:50:05 +0200, Brendan Eich <brendan at>  

> Let's get back to the problems with JS functions:
> 3. Tennent's principle of abstraction violations other than 'this'.

Why is this a *problem*?

I see having fully general non-local returns as a bigger problem than not  
having them.

If you can declare a function inside another, let the inner function  
escape and survive the outer, and is then allowed to try to return from  
the outer function again ... that's simply bad. Just throwing an exception  
seems a meek response to a fatal logical flaw.

Closures capture the variable environment of their point of declaration.  
That's possible because the environment chain (if not the content of it)  
is actually statically defined at the time the function closure is  
created. It will keep making sense, no matter what happens later.

The stack frames/program counter/other dynamic behavior cannot be  
meaningfully captured in the same way. It's not guaranteed to be the same  
when the inner function is eventually called, or to even exist any more.
It's possible to define the language in such a way that this would make  
sense, by snapshotting the dynamic state, but that would effectively  
introduce call/cc, which seems like a overdoing it.
Exceptions work because they are defined in terms of the dynamic control  
flow, not syntactic inclusion. Making a non-local return from an inner  
function is just as senseless as expecting a syntactically containing  
try/catch to catch a thrown exception.

The usecase generally used for non-local returns are user-implemented  
control flow operators. This use would typically require only down-calls,  
where all calls to the closure are performed inside the same invocation of  
the calling function.
That's actually just a hack for emulating real call-by-name (which is what  
best corresponds to the behavior of the built-in
control from operators like "for" and "while"). But even that can be  
foiled, if you can capture a call-by-name argument
in a closure.

The current abstraction: function, function call and return, works so well  
because it does what it does well - abstract
a statement with a single entry and a single exit (excepting exceptions  
ofcourse :), which means that it can be used
wherever a statement can be used. Or an expression, if it returns a value.  
It's a clean abstraction.

Adding non-local control-flow to a function allows it to have more than  
one exit. It means that expressions can now
break or continue a loop, or return from the local function, where before  
only statements could.

I think this got more confusing than I had hoped it would.
I guess the summary would be: I don't think Tennent's principle of  
abstraction can be meaningfully applied to control flow when your  
abstraction can survive the control flow that created it.

/L 'but "this" is a problem that is fixable'
Lasse Reichstein - reichsteinatwork at

More information about the es-discuss mailing list