Short Functions

Claus Reinke claus.reinke at talk21.com
Sun May 22 07:12:55 PDT 2011


>> the other is a much more radical change to the way 
>> the language works, which I'm not altogether 
>> convinced is a good or useful thing.

> It's essential to the control abstraction programmability. 
> Take a look at the examples. .. Return from a block in JS 
> today returns from the enclosing function. Same for 
> return from a block-lambda in a function. It's an early 
> error to return from global code, and will be in a 
> block-lambda in global code.
> 
> Why is this so bad? JS programmers return, break, 
> and continue from blocks all the time.

The examples focus on inline uses of block_lambdas,
but block_lambdas can do a lot more than that (or so I 
think - until we see more complete semantics, I have to 
extrapolate from the examples; perhaps the variations 
below are not intended). Again, that doesn't have to be 
bad, but the consequences need to be investigated and 
taken into consideration.

For instance, block_lambdas seem to include a form of 
generalized jump, a callable thing that does not return 
to the caller (Tennent mentioned such things as 'sequels',
so they were probably known in Algol times, but I have
not seen them implemented, short of (delimited) continuations).
We just need to ensure that the callable's definition context 
is still active:

function A() {
    let ret = {|x| return x; }; // sequel
    let inc = {|x| x+1 };    // function
    let j = 0;
    while(true) {
        if (j > 3)
            ret(j); // leave loop, and A
        else
            j = inc(j); // continue loop
    }
}

Calling a sequel like 'ret' is always a tail call, because 
it never returns to the caller, it returns elsewhere. In
that sense, it is a generalized jump.

The break/continue variant of sequels also makes it 
possible to replace labeled breaks and continues with 
sequels:

A: while(true) {
    let continue_A = {|| continue; };
    B: while (true) {
        let break_B = {|| break; }; 
        C: while(true) {
            if (cond)
                continue_A();
            else
                break_B();
        }
    }
}

The best approximation I have of what return/break/continue
mean in a block_lambda is based on lexical scoping, to the 
nearest enclosing function or loop (but nullable: when the 
definition context is no longer active, return/break/continue
throw a runtime error). 

That means that functions and loops have implicit bindings
(for return and for break/continue), and the 'break_B' example 
above is really analogous to the 'let self = this;' pattern: a way
ot keeping the next outer implicit binding accessible. Of course, 
block_lambdas do not introduce this problem, they introduce 
a new workaround. Still, it is interesting to look at the new
programming patterns that become possible.

Again, this is just guessing based on reading the examples 
in the strawman - it could be completely off the mark. Informal 
but complete semantics would help to understand what is 
supposed to be possible and what not. Further decisions 
cannot be based on syntax or selected examples alone.

Claus

 


More information about the es-discuss mailing list