Allen Wirfs-Brock (2015-02-23T16:40:19.000Z)
On Feb 23, 2015, at 7:22 AM, Mark S. Miller wrote:

> We still an an option open to us, that would merely compatibly remove a restriction from the language rather than add a feature: Allow labels to remain visible across function boundaries, or at least across arrow function boundaries. Then one could break-to-label to a label of a lexically enclosing function.
> 
> This has repeatedly died in committee before because it does raise another case for implementors: Once the execution context of that label has completed, an attempt to break to that label must instead throw an error. I've never understood why this extra case was a show stopper.
> 
> Previous iterations of the proposal never raised the possibility of restricting this new ability to arrow functions. I don't see why we should, but I can see why it would seem more parsimonious -- since arrow functions are trying to be much more TCB than other functions. Perhaps that restriction will make this more palatable? In any case, even if we first allow this only for arrow functions, we'd still have the option to compatibly remove the restriction for other functions later.
> 
> My other suspicion: The previous failure of this proposal was before many people had much hands on experience using higher order functions in JS as a normal alternative to control structures. Now that we all have, the need for a non-local escape may be more visceral.
> 

We actually explored this  alternative quite extensively prior to adopting arrow functions and had "block lambdas" with label support pretty much fully spec'ed.  What killed them for me wasn't issues involving BLs that outlived their home function, that was easy enough to deal with.  The major problem was the complexity involved in making labelled early exit syntax (break and particularly continue) work as might be expected when used in the context of control abstraction functions.  For example, consider:

for (v of O) {
   CtlLib.doWhile(()=>true, () {
        if (  condition1(v) break;
        if (condition2(v) continue;
        //do something here
    });
}

or

outer: for (v of O) {
   inner: CtlLib.doWhile(()=>true, () {
        if (  condition1(v) break outer;
        if (condition2(v) continue inner;
        //do something here
    });
}


What should happen for the 'break' and 'continue'?  What will a programmer think should happen.  If we really are claiming TC for such arrows, then presumably programmers should be thinking about abstractions like CtlLib.doWhile as being on the same footing as built-in syntactic control structures such as the 'while' statement.   In that case, a reasonable (more strongly put, necessary) expectation is that unlabeled break/continue must refer to the closest enclosing control structure which is the  DtlLib.doWhile.  

To make that work, means that the control abstraction function must have an opportunity to define what it means for it to 'continue' . Accomplishing that requires coming up with a way for reify the specification's "completion value" mechanism and labeling semantics so that the JS code can intercept and respond to them. For example, it probably requires some like a labelledArray(labelSet, thisValue, args) function for invoking a function with the intent of receiving a reified completion value.  There were also issues relating to possible interactions between labeled syntactic control structures used by the control abstraction function itself and  the use of labels and early exits by the consumer of the control abstract. 

This would have added significant complexity to the language.  It also adds significant complexity for the implementors of control abstraction functions.

For me, at least, this passed the point of diminishing returns. 

There is a fork in the road of language design, you can take the fork of c-style syntactic control structures with labeled early exits. Or you can take the path of user definable control abstraction functions built upon TCP.  Each path works well, within the bounds of its particular limitations. But trying to rejoin those two paths in a manner that combines all the features of both leads you into a complexity swamp.

Allen



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150223/7d171d71/attachment.html>
d at domenic.me (2015-03-06T00:49:32.950Z)
We actually explored this  alternative quite extensively prior to adopting arrow functions and had "block lambdas" with label support pretty much fully spec'ed.  What killed them for me wasn't issues involving BLs that outlived their home function, that was easy enough to deal with.  The major problem was the complexity involved in making labelled early exit syntax (break and particularly continue) work as might be expected when used in the context of control abstraction functions.  For example, consider:

```js
for (v of O) {
   CtlLib.doWhile(()=>true, () {
        if (  condition1(v) break;
        if (condition2(v) continue;
        //do something here
    });
}
```

or

```js
outer: for (v of O) {
   inner: CtlLib.doWhile(()=>true, () {
        if (  condition1(v) break outer;
        if (condition2(v) continue inner;
        //do something here
    });
}
```

What should happen for the 'break' and 'continue'?  What will a programmer think should happen.  If we really are claiming TC for such arrows, then presumably programmers should be thinking about abstractions like CtlLib.doWhile as being on the same footing as built-in syntactic control structures such as the 'while' statement.   In that case, a reasonable (more strongly put, necessary) expectation is that unlabeled break/continue must refer to the closest enclosing control structure which is the  DtlLib.doWhile.  

To make that work, means that the control abstraction function must have an opportunity to define what it means for it to 'continue' . Accomplishing that requires coming up with a way for reify the specification's "completion value" mechanism and labeling semantics so that the JS code can intercept and respond to them. For example, it probably requires some like a labelledArray(labelSet, thisValue, args) function for invoking a function with the intent of receiving a reified completion value.  There were also issues relating to possible interactions between labeled syntactic control structures used by the control abstraction function itself and  the use of labels and early exits by the consumer of the control abstract. 

This would have added significant complexity to the language.  It also adds significant complexity for the implementors of control abstraction functions.

For me, at least, this passed the point of diminishing returns. 

There is a fork in the road of language design, you can take the fork of c-style syntactic control structures with labeled early exits. Or you can take the path of user definable control abstraction functions built upon TCP.  Each path works well, within the bounds of its particular limitations. But trying to rejoin those two paths in a manner that combines all the features of both leads you into a complexity swamp.