Block Lambdas: break and continue

Brendan Eich brendan at mozilla.org
Sat Jan 14 13:44:10 PST 2012


> François REMY <mailto:fremycompany_pub at yahoo.fr>
> January 14, 2012 1:31 PM
> Thanks for your reply. I think you misunderstood the whole concept.

Could be, or perhaps you misunderstood my reply to Herby's message, 
which had nothing to do with the ax you are grinding :-|.


> The idea would not to implement that for Arrays. Arrays already have 
> their own semantics.

Look back up the thread (or down the cited messages below -- but I think 
I'll trim the overciting) and see Axel bringing up Array forEach as the 
use-case for dynamic break and continue semantics in block-lambdas.

I appreciate your repair via "throw break" and "throw continue" to 
restore TCP. That's not at issue.

What is at issue is the cost/benefit analysis, which does depend on 
developer ergonomics of exceptions, including as block-lambdas that 
throw break or throw continue might work (or not) with Array extras.

You cannot _a priori_ exclude complex scenarios by wishing for better 
programmers, or programmers who use new functional styles and only new 
APIs, and buy into the complexity of the new exceptions. At least, Ecma 
TC39 cannot.

We have to consider how poorly or well exceptions are used today, how 
developers might use them tomorrow, what reasonable (see Axel's post) 
expectations they might have for Array extras called with block-lambdas.

The throw break and throw continue ideas are coherent and we could 
design them into a future spec. I have no doubt about this. But I do not 
think the complexity, for developers first but also for implementors 
(and last for the spec editors) is worth it.
> I think the idea about Block Lamdba is to introduce functionnal 
> programming concepts to ECMAScript.

Not really. JS is used in function-programming styles (there's more than 
one) already.

What block-lambdas aim to do is provide much sweeter downward-funarg 
syntax and semantics, which aids refactoring and reasoning about such 
"synchronous callback" code.

Block-lambdas may be used with asynchronous callback code too, with the 
benefits of |this| invariance and completion-return.

This is not a big new functional-programming concept push. It's a 
usability and safety (wrong-this bugs are bad) win for many (not all) 
uses of function-expressions-as-callbacks we see today.

> It’s it’s the case, developers will want to implement their own kind 
> of Head|Queue stream. For exemple, a webworker computing values and 
> calling the callback with the computed value each time he output a new 
> one (using a postMessage channel). The problem is that you may need to 
> have a way to say to the WebWorker “OK, I want to break the loop, I’ve 
> what I need, please stop computing and free memory.” You could use 
> your own “throw” pattern but using a standard one could be useful for 
> code reuse.

I'd say that differently: for such hard cases, throw already exists. The 
burden is on the proposer to show this is common enough to justify 
making break and continue, or in your proposal, new "throw break" and 
"throw continue" forms, throw new exceptions.

The problem is not just the cost of adding new forms (let's say your 
proposal wins -- it is much better than redefining break and continue to 
throw).

The issue I'm raising is the consequence on "looping" and "wrapper" 
functions in common use (whether Array forEach or JQuery each or 
something new next year or bespoke in a private codebase) of introducing 
such new exceptions as standards.

Let the worker hard case use "throw" and its own sentinel object, and 
let's see how common and non-hard this case becomes. I doubt it will 
grow to become much seen.

(Indeed I hope it is supplanted by better concurrency structures than 
workers, and we're laboring to develop such things. But whatever happens 
there, this use-case is not obviously common enough to be worth a change 
with global effects.)

/be
> I hope I was clear,
> François
> *From:* Brendan Eich <mailto:brendan at mozilla.org>
> *Sent:* Saturday, January 14, 2012 10:16 PM
> *To:* François REMY <mailto:fremycompany_pub at yahoo.fr>
> *Cc:* Herby Vojčík <mailto:herby at mailbox.sk> ; es-discuss at mozilla.org 
> <mailto:es-discuss at mozilla.org>
> *Subject:* Re: Block Lambdas: break and continue
>> François REMY <mailto:fremycompany_pub at yahoo.fr>
>> January 14, 2012 1:01 PM
>> If we want to avoid to break TCP, we can go with “throw break;” and 
>> “throw continue;”.
>
> This doesn't address Herby's TCP-violating wish for a non-return that  
> completes the block-lambda's control flow normally with a value (the 
> message to which I was replying). But you're right that it wouldn't 
> violate TCP either if we support it the same in a block statement as 
> in a block-lambda downward funarg.
>
>> It would throw a new BreakException or a new ContinueException, from 
>> the place where they are executed. If it’s outside a block lambda, 
>> it’s outside a block lambda. It doesn’t matter.
>
> Yes, this would avoid TCP violations but not carry a return value -- 
> Herby's wish.
>> But it would set a “standard” for breaking throug ‘function loops’.
>
> I considered this in drafting the block-lambda revival strawman. Other 
> languages have gone here. Nevertheless, I would like to leave it out 
> (remember N. Wirth on language design). It adds more complexity for a 
> use-case that I bet is rare (in any case it needs credible 
> demonstration of being quite common).
>
> The complexity in the semantics is one issue Dave raised. This 
> corresponds to complexity for optimizing engines, compared to the 
> purely static break/continue semantics in the strawman.
>
> Finally, the Array extras ship sailed. People already have to use some 
> or every in lieu of a break-from-forEach. Using a function callback 
> with forEach, one needs only to return to simulate continue. Now if we 
> do standardize block-lambdas and throw break or throw continue, we 
> certainly can elaborate the extras to catch these exceptions.
>
> Such a more complex design seems workable with the costs noted above. 
> But will the benefits really outweigh those costs? I doubt it. First, 
> Array forEach and other uses will continue to use functions for quite 
> a while, or else a compiler from new standard JS to old. In the 
> compiler case, throw and try/catch will be required, and the compiler 
> will have to monkey-patch the extras to deal with the new exceptions. 
> This will be a performance killer, and no fun to debug.
>
> So my thinking remains that we are better off, when in doubt, leaving 
> reified break and continue exceptions "out".
>
> /be
>
>> François
>> *From:* Brendan Eich <mailto:brendan at mozilla.org>
>> *Sent:* Saturday, January 14, 2012 9:51 PM
>> *To:* Herby Vojčík <mailto:herby at mailbox.sk>
>> *Cc:* es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>> *Subject:* Re: Block Lambdas: break and continue
>>> Herby Vojčík <mailto:herby at mailbox.sk>
>>> January 14, 2012 10:42 AM
>>> === David Herman wrote ===
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>> ===
>>>
>>> What about the exception-less suggestion I put in? It should work in 
>>> any loop construct with lambda-block, even if you must know a little 
>>> about the loop implementation itself. That is, to be able to put:
>>>
>>>    continue |expression|;
>>
>> Who says the block-lambda is being called from a loop at all? Why 
>> should use-cases that want an early result and completion have to use 
>> continue, which is for loops?
>>
>> Worse, this violates TCP. Now you copy and paste this block-lambda 
>> code back into a block statement to refactor the other direction, and 
>> no such "here is the completion value, do not flow past this point in 
>> the block" semantics obtain.
>>>
>>> as a statement in lambda block which instructs the lambda-block 
>>> itself (not the outer function) to return the expression? This is 
>>> the de-facto continue semantics (lambda-block, do return a value and 
>>> the enclosing loop will continue to the next iteration (possibly 
>>> stopping the loop if it chooses not to have more iterations)).
>>
>> No it's not. There is no de-facto continue semantics for 
>> block-lambdas because they haven't been prototyped. For block 
>> statements, no such continue semantics exists.
>>
>>> It is not possible to enforce break in the same manner, but for 
>>> continue, it is possible.
>>
>> It's possible to abuse any existing keyword, but first: why must 
>> there be a new TCP violation? Block-lambda bodies are often 
>> expressions, or if statements, then short/functional-style 
>> statements, not large bodies demonstrating early-normal-completion 
>> opportunities.
>>
>> We should not eliminate TCP violations only to add new ones, 
>> especially without any evidence they're needed and pay their way. 
>> Otherwise we'll get an infinite regress of 
>> TCP-pure-then-add-new-exceptions-and-repeat additions.
>>
>> /be
>>>
>>> Herby
>>>
>>> -----Pôvodná správa----- From: David Herman
>>> Sent: Saturday, January 14, 2012 6:12 PM
>>> To: Axel Rauschmayer
>>> Cc: Brendan Eich ; es-discuss at mozilla.org
>>> Subject: Re: Block Lambdas: break and continue
>>>
>>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>>
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>>    Array.prototype.forEach = function(f) {
>>>        for (let i = 0, n = this.length; i < n; i++) {
>>>            try {
>>>                f.call(this, this[i], i);
>>>            } catch (e) {
>>>                if (e instanceof BreakException)
>>>                    break;
>>>                else if (e instanceof ContinueException)
>>>                    continue;
>>>                else
>>>                    throw e;
>>>            }
>>>        }
>>>    };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> David Herman <mailto:dherman at mozilla.com>
>>> January 14, 2012 9:12 AM
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>> Array.prototype.forEach = function(f) {
>>> for (let i = 0, n = this.length; i < n; i++) {
>>> try {
>>> f.call(this, this[i], i);
>>> } catch (e) {
>>> if (e instanceof BreakException)
>>> break;
>>> else if (e instanceof ContinueException)
>>> continue;
>>> else
>>> throw e;
>>> }
>>> }
>>> };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>>
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 13, 2012 9:04 PM
>>> I think it’s a valid concern. The idea is: If I can implement my own 
>>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>>> I also want those loops to have break and continue. You could 
>>> statically determine what construct, say, a break applies to and 
>>> either throw a BreakException (if it applies to a lambda) or 
>>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>>> examples below, when I see a continue, I look for the innermost 
>>> enclosing loop braces and the ones belong to list[i].forEach are 
>>> definitely candidates.
>>> -- 
>>> Dr. Axel Rauschmayer
>>> axel at rauschma.de <mailto:axel at rauschma.de>
>>> home: rauschma.de <http://rauschma.de>
>>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>>> blog: 2ality.com <http://2ality.com>
>>> Brendan Eich <mailto:brendan at mozilla.org>
>>> January 13, 2012 8:54 PM
>>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>>> January 13, 2012 7:29 PM
>>>> Block lambdas have been a hot topic, recently, but there's a point 
>>>> of significant divergence between Ruby (which appears to be the 
>>>> inspiration)
>>>
>>> Not Ruby alone, and not in any chauvinist my-language-is-better 
>>> sense. Smalltalk is the original inspiration for Ruby blocks, and 
>>> the correspondence principle has deep roots.
>>>
>>>> and the proposed solution, in the handling of continue (called 
>>>> 'next', in Ruby) and 'break'.
>>>> To whit: In Ruby, 'next' will end the current run (iteration) of 
>>>> the block, and 'break' will (somehow) terminate the method 
>>>> lexically connected with the block. It can be claimed that this is 
>>>> more intuitive than the current proposal, which aims to make 
>>>> 'break' and 'continue' propagate through block lambdas in the same 
>>>> way 'return' would.
>>>
>>> "Intuitive" depends on intuition, which is not well-defined. Do you 
>>> mean a Rubyist might expect different behavior for break? That is 
>>> possible but JS ain't Ruby and break should not change to do 
>>> something like what it does in Ruby (and we aren't defining a next 
>>> equivalent for JS).
>>>
>>>> Ruby does also support syntactic loops and the same keywords 
>>>> therein and so directly violates Tennent's Correspondence 
>>>> Principle, even though such has been touted as a core reason for 
>>>> the construct. Instead, I believe it reasonable to invoke intuition 
>>>> in this matter. It is intuitive for 'return' to return a value from 
>>>> the lexically enclosing method and it is intuitive for 'continue' 
>>>> to commence the next iteration of the current loop,
>>>
>>> Wait, why do you think break and continue without label operands do 
>>> anything other than break from the nearest enclosing loop (or switch 
>>> or labeled statement if break), or continue the nearest enclosing 
>>> loop? The proposal specifies this.
>>>
>>> function find_odds_in_arrays(list,        // array of arrays
>>>                              skip)        // if found, skip rest
>>> {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === skip) {
>>>         continue;                         // continue the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>> function find_more_odds(list, stop) {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === stop) {
>>>         break;                      // break from the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>>> however that loop is constructed.
>>>
>>> What do you mean by this? The spec talks about nearest enclosing 
>>> loop or relevant control structure in the source code. Are you 
>>> talking about internal loops in implementations (dynamically 
>>> dispatched at that) of methods that take block-lambdas as arguments? 
>>> I.e.
>>>
>>>
>>> function find_first_odd(a) {
>>>   a.forEach { |e, i|
>>>               if (e & 1) return i; }  // returns from function
>>>   return -1;
>>> }
>>>
>>>
>>> The Array.prototype.forEach method's internal implementation is its 
>>> business, and a break instead of the return would be a static error 
>>> in this example. It would not be a dynamic throw-like construct that 
>>> is caught by forEach's implementation.
>>>
>>> /be
>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>> January 13, 2012 7:29 PM
>>> Block lambdas have been a hot topic, recently, but there's a point 
>>> of significant divergence between Ruby (which appears to be the 
>>> inspiration) and the proposed solution, in the handling of continue 
>>> (called 'next', in Ruby) and 'break'.
>>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>>> block, and 'break' will (somehow) terminate the method lexically 
>>> connected with the block. It can be claimed that this is more 
>>> intuitive than the current proposal, which aims to make 'break' and 
>>> 'continue' propagate through block lambdas in the same way 'return' 
>>> would.
>>> Ruby does also support syntactic loops and the same keywords therein 
>>> and so directly violates Tennent's Correspondence Principle, even 
>>> though such has been touted as a core reason for the construct. 
>>> Instead, I believe it reasonable to invoke intuition in this matter. 
>>> It is intuitive for 'return' to return a value from the lexically 
>>> enclosing method and it is intuitive for 'continue' to commence the 
>>> next iteration of the current loop, however that loop is constructed.
>>> Note that the label-based break/continue could still have the 
>>> desired effect, if the proposal was updated to be more like Ruby's 
>>> blocks.
>>> I don't have a strong opinion on the subject, but I hadn't noticed 
>>> the above being discussed, elsewhere, and thought it worth raising. 
>>> If there is a better place for me to raise this, please let me know 
>>> where and accept my apologies.
>>> Regards,
>>> Grant Husbands.
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>> ------------------------------------------------------------------------
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 14, 2012 12:51 PM
>>> Herby Vojčík <mailto:herby at mailbox.sk>
>>> January 14, 2012 10:42 AM
>>> === David Herman wrote ===
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>> ===
>>>
>>> What about the exception-less suggestion I put in? It should work in 
>>> any loop construct with lambda-block, even if you must know a little 
>>> about the loop implementation itself. That is, to be able to put:
>>>
>>>    continue |expression|;
>>
>> Who says the block-lambda is being called from a loop at all? Why 
>> should use-cases that want an early result and completion have to use 
>> continue, which is for loops?
>>
>> Worse, this violates TCP. Now you copy and paste this block-lambda 
>> code back into a block statement to refactor the other direction, and 
>> no such "here is the completion value, do not flow past this point in 
>> the block" semantics obtain.
>>>
>>> as a statement in lambda block which instructs the lambda-block 
>>> itself (not the outer function) to return the expression? This is 
>>> the de-facto continue semantics (lambda-block, do return a value and 
>>> the enclosing loop will continue to the next iteration (possibly 
>>> stopping the loop if it chooses not to have more iterations)).
>>
>> No it's not. There is no de-facto continue semantics for 
>> block-lambdas because they haven't been prototyped. For block 
>> statements, no such continue semantics exists.
>>
>>> It is not possible to enforce break in the same manner, but for 
>>> continue, it is possible.
>>
>> It's possible to abuse any existing keyword, but first: why must 
>> there be a new TCP violation? Block-lambda bodies are often 
>> expressions, or if statements, then short/functional-style 
>> statements, not large bodies demonstrating early-normal-completion 
>> opportunities.
>>
>> We should not eliminate TCP violations only to add new ones, 
>> especially without any evidence they're needed and pay their way. 
>> Otherwise we'll get an infinite regress of 
>> TCP-pure-then-add-new-exceptions-and-repeat additions.
>>
>> /be
>>>
>>> Herby
>>>
>>> -----Pôvodná správa----- From: David Herman
>>> Sent: Saturday, January 14, 2012 6:12 PM
>>> To: Axel Rauschmayer
>>> Cc: Brendan Eich ; es-discuss at mozilla.org
>>> Subject: Re: Block Lambdas: break and continue
>>>
>>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>>
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>>    Array.prototype.forEach = function(f) {
>>>        for (let i = 0, n = this.length; i < n; i++) {
>>>            try {
>>>                f.call(this, this[i], i);
>>>            } catch (e) {
>>>                if (e instanceof BreakException)
>>>                    break;
>>>                else if (e instanceof ContinueException)
>>>                    continue;
>>>                else
>>>                    throw e;
>>>            }
>>>        }
>>>    };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> David Herman <mailto:dherman at mozilla.com>
>>> January 14, 2012 9:12 AM
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>> Array.prototype.forEach = function(f) {
>>> for (let i = 0, n = this.length; i < n; i++) {
>>> try {
>>> f.call(this, this[i], i);
>>> } catch (e) {
>>> if (e instanceof BreakException)
>>> break;
>>> else if (e instanceof ContinueException)
>>> continue;
>>> else
>>> throw e;
>>> }
>>> }
>>> };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>>
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 13, 2012 9:04 PM
>>> I think it’s a valid concern. The idea is: If I can implement my own 
>>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>>> I also want those loops to have break and continue. You could 
>>> statically determine what construct, say, a break applies to and 
>>> either throw a BreakException (if it applies to a lambda) or 
>>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>>> examples below, when I see a continue, I look for the innermost 
>>> enclosing loop braces and the ones belong to list[i].forEach are 
>>> definitely candidates.
>>> -- 
>>> Dr. Axel Rauschmayer
>>> axel at rauschma.de <mailto:axel at rauschma.de>
>>> home: rauschma.de <http://rauschma.de>
>>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>>> blog: 2ality.com <http://2ality.com>
>>> Brendan Eich <mailto:brendan at mozilla.org>
>>> January 13, 2012 8:54 PM
>>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>>> January 13, 2012 7:29 PM
>>>> Block lambdas have been a hot topic, recently, but there's a point 
>>>> of significant divergence between Ruby (which appears to be the 
>>>> inspiration)
>>>
>>> Not Ruby alone, and not in any chauvinist my-language-is-better 
>>> sense. Smalltalk is the original inspiration for Ruby blocks, and 
>>> the correspondence principle has deep roots.
>>>
>>>> and the proposed solution, in the handling of continue (called 
>>>> 'next', in Ruby) and 'break'.
>>>> To whit: In Ruby, 'next' will end the current run (iteration) of 
>>>> the block, and 'break' will (somehow) terminate the method 
>>>> lexically connected with the block. It can be claimed that this is 
>>>> more intuitive than the current proposal, which aims to make 
>>>> 'break' and 'continue' propagate through block lambdas in the same 
>>>> way 'return' would.
>>>
>>> "Intuitive" depends on intuition, which is not well-defined. Do you 
>>> mean a Rubyist might expect different behavior for break? That is 
>>> possible but JS ain't Ruby and break should not change to do 
>>> something like what it does in Ruby (and we aren't defining a next 
>>> equivalent for JS).
>>>
>>>> Ruby does also support syntactic loops and the same keywords 
>>>> therein and so directly violates Tennent's Correspondence 
>>>> Principle, even though such has been touted as a core reason for 
>>>> the construct. Instead, I believe it reasonable to invoke intuition 
>>>> in this matter. It is intuitive for 'return' to return a value from 
>>>> the lexically enclosing method and it is intuitive for 'continue' 
>>>> to commence the next iteration of the current loop,
>>>
>>> Wait, why do you think break and continue without label operands do 
>>> anything other than break from the nearest enclosing loop (or switch 
>>> or labeled statement if break), or continue the nearest enclosing 
>>> loop? The proposal specifies this.
>>>
>>> function find_odds_in_arrays(list,        // array of arrays
>>>                              skip)        // if found, skip rest
>>> {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === skip) {
>>>         continue;                         // continue the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>> function find_more_odds(list, stop) {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === stop) {
>>>         break;                      // break from the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>>> however that loop is constructed.
>>>
>>> What do you mean by this? The spec talks about nearest enclosing 
>>> loop or relevant control structure in the source code. Are you 
>>> talking about internal loops in implementations (dynamically 
>>> dispatched at that) of methods that take block-lambdas as arguments? 
>>> I.e.
>>>
>>>
>>> function find_first_odd(a) {
>>>   a.forEach { |e, i|
>>>               if (e & 1) return i; }  // returns from function
>>>   return -1;
>>> }
>>>
>>>
>>> The Array.prototype.forEach method's internal implementation is its 
>>> business, and a break instead of the return would be a static error 
>>> in this example. It would not be a dynamic throw-like construct that 
>>> is caught by forEach's implementation.
>>>
>>> /be
>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>> January 13, 2012 7:29 PM
>>> Block lambdas have been a hot topic, recently, but there's a point 
>>> of significant divergence between Ruby (which appears to be the 
>>> inspiration) and the proposed solution, in the handling of continue 
>>> (called 'next', in Ruby) and 'break'.
>>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>>> block, and 'break' will (somehow) terminate the method lexically 
>>> connected with the block. It can be claimed that this is more 
>>> intuitive than the current proposal, which aims to make 'break' and 
>>> 'continue' propagate through block lambdas in the same way 'return' 
>>> would.
>>> Ruby does also support syntactic loops and the same keywords therein 
>>> and so directly violates Tennent's Correspondence Principle, even 
>>> though such has been touted as a core reason for the construct. 
>>> Instead, I believe it reasonable to invoke intuition in this matter. 
>>> It is intuitive for 'return' to return a value from the lexically 
>>> enclosing method and it is intuitive for 'continue' to commence the 
>>> next iteration of the current loop, however that loop is constructed.
>>> Note that the label-based break/continue could still have the 
>>> desired effect, if the proposal was updated to be more like Ruby's 
>>> blocks.
>>> I don't have a strong opinion on the subject, but I hadn't noticed 
>>> the above being discussed, elsewhere, and thought it worth raising. 
>>> If there is a better place for me to raise this, please let me know 
>>> where and accept my apologies.
>>> Regards,
>>> Grant Husbands.
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>> Herby Vojčík <mailto:herby at mailbox.sk>
>> January 14, 2012 10:42 AM
>> === David Herman wrote ===
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>> ===
>>
>> What about the exception-less suggestion I put in? It should work in 
>> any loop construct with lambda-block, even if you must know a little 
>> about the loop implementation itself. That is, to be able to put:
>>
>>    continue |expression|;
>>
>> as a statement in lambda block which instructs the lambda-block 
>> itself (not the outer function) to return the expression? This is the 
>> de-facto continue semantics (lambda-block, do return a value and the 
>> enclosing loop will continue to the next iteration (possibly stopping 
>> the loop if it chooses not to have more iterations)). It is not 
>> possible to enforce break in the same manner, but for continue, it is 
>> possible.
>>
>> Herby
>>
>> -----Pôvodná správa----- From: David Herman
>> Sent: Saturday, January 14, 2012 6:12 PM
>> To: Axel Rauschmayer
>> Cc: Brendan Eich ; es-discuss at mozilla.org
>> Subject: Re: Block Lambdas: break and continue
>>
>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>>    Array.prototype.forEach = function(f) {
>>        for (let i = 0, n = this.length; i < n; i++) {
>>            try {
>>                f.call(this, this[i], i);
>>            } catch (e) {
>>                if (e instanceof BreakException)
>>                    break;
>>                else if (e instanceof ContinueException)
>>                    continue;
>>                else
>>                    throw e;
>>            }
>>        }
>>    };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>> David Herman <mailto:dherman at mozilla.com>
>> January 14, 2012 9:12 AM
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>> Array.prototype.forEach = function(f) {
>> for (let i = 0, n = this.length; i < n; i++) {
>> try {
>> f.call(this, this[i], i);
>> } catch (e) {
>> if (e instanceof BreakException)
>> break;
>> else if (e instanceof ContinueException)
>> continue;
>> else
>> throw e;
>> }
>> }
>> };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>>
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 13, 2012 9:04 PM
>> I think it’s a valid concern. The idea is: If I can implement my own 
>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>> I also want those loops to have break and continue. You could 
>> statically determine what construct, say, a break applies to and 
>> either throw a BreakException (if it applies to a lambda) or 
>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>> examples below, when I see a continue, I look for the innermost 
>> enclosing loop braces and the ones belong to list[i].forEach are 
>> definitely candidates.
>> -- 
>> Dr. Axel Rauschmayer
>> axel at rauschma.de <mailto:axel at rauschma.de>
>> home: rauschma.de <http://rauschma.de>
>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>> blog: 2ality.com <http://2ality.com>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> Brendan Eich <mailto:brendan at mozilla.org>
> January 14, 2012 1:16 PM
>> François REMY <mailto:fremycompany_pub at yahoo.fr>
>> January 14, 2012 1:01 PM
>> If we want to avoid to break TCP, we can go with “throw break;” and 
>> “throw continue;”.
>
> This doesn't address Herby's TCP-violating wish for a non-return that  
> completes the block-lambda's control flow normally with a value (the 
> message to which I was replying). But you're right that it wouldn't 
> violate TCP either if we support it the same in a block statement as 
> in a block-lambda downward funarg.
>
>> It would throw a new BreakException or a new ContinueException, from 
>> the place where they are executed. If it’s outside a block lambda, 
>> it’s outside a block lambda. It doesn’t matter.
>
> Yes, this would avoid TCP violations but not carry a return value -- 
> Herby's wish.
>> But it would set a “standard” for breaking throug ‘function loops’.
>
> I considered this in drafting the block-lambda revival strawman. Other 
> languages have gone here. Nevertheless, I would like to leave it out 
> (remember N. Wirth on language design). It adds more complexity for a 
> use-case that I bet is rare (in any case it needs credible 
> demonstration of being quite common).
>
> The complexity in the semantics is one issue Dave raised. This 
> corresponds to complexity for optimizing engines, compared to the 
> purely static break/continue semantics in the strawman.
>
> Finally, the Array extras ship sailed. People already have to use some 
> or every in lieu of a break-from-forEach. Using a function callback 
> with forEach, one needs only to return to simulate continue. Now if we 
> do standardize block-lambdas and throw break or throw continue, we 
> certainly can elaborate the extras to catch these exceptions.
>
> Such a more complex design seems workable with the costs noted above. 
> But will the benefits really outweigh those costs? I doubt it. First, 
> Array forEach and other uses will continue to use functions for quite 
> a while, or else a compiler from new standard JS to old. In the 
> compiler case, throw and try/catch will be required, and the compiler 
> will have to monkey-patch the extras to deal with the new exceptions. 
> This will be a performance killer, and no fun to debug.
>
> So my thinking remains that we are better off, when in doubt, leaving 
> reified break and continue exceptions "out".
>
> /be
>
>> François
>> *From:* Brendan Eich <mailto:brendan at mozilla.org>
>> *Sent:* Saturday, January 14, 2012 9:51 PM
>> *To:* Herby Vojčík <mailto:herby at mailbox.sk>
>> *Cc:* es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>> *Subject:* Re: Block Lambdas: break and continue
>>> Herby Vojčík <mailto:herby at mailbox.sk>
>>> January 14, 2012 10:42 AM
>>> === David Herman wrote ===
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>> ===
>>>
>>> What about the exception-less suggestion I put in? It should work in 
>>> any loop construct with lambda-block, even if you must know a little 
>>> about the loop implementation itself. That is, to be able to put:
>>>
>>>    continue |expression|;
>>
>> Who says the block-lambda is being called from a loop at all? Why 
>> should use-cases that want an early result and completion have to use 
>> continue, which is for loops?
>>
>> Worse, this violates TCP. Now you copy and paste this block-lambda 
>> code back into a block statement to refactor the other direction, and 
>> no such "here is the completion value, do not flow past this point in 
>> the block" semantics obtain.
>>>
>>> as a statement in lambda block which instructs the lambda-block 
>>> itself (not the outer function) to return the expression? This is 
>>> the de-facto continue semantics (lambda-block, do return a value and 
>>> the enclosing loop will continue to the next iteration (possibly 
>>> stopping the loop if it chooses not to have more iterations)).
>>
>> No it's not. There is no de-facto continue semantics for 
>> block-lambdas because they haven't been prototyped. For block 
>> statements, no such continue semantics exists.
>>
>>> It is not possible to enforce break in the same manner, but for 
>>> continue, it is possible.
>>
>> It's possible to abuse any existing keyword, but first: why must 
>> there be a new TCP violation? Block-lambda bodies are often 
>> expressions, or if statements, then short/functional-style 
>> statements, not large bodies demonstrating early-normal-completion 
>> opportunities.
>>
>> We should not eliminate TCP violations only to add new ones, 
>> especially without any evidence they're needed and pay their way. 
>> Otherwise we'll get an infinite regress of 
>> TCP-pure-then-add-new-exceptions-and-repeat additions.
>>
>> /be
>>>
>>> Herby
>>>
>>> -----Pôvodná správa----- From: David Herman
>>> Sent: Saturday, January 14, 2012 6:12 PM
>>> To: Axel Rauschmayer
>>> Cc: Brendan Eich ; es-discuss at mozilla.org
>>> Subject: Re: Block Lambdas: break and continue
>>>
>>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>>
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>>    Array.prototype.forEach = function(f) {
>>>        for (let i = 0, n = this.length; i < n; i++) {
>>>            try {
>>>                f.call(this, this[i], i);
>>>            } catch (e) {
>>>                if (e instanceof BreakException)
>>>                    break;
>>>                else if (e instanceof ContinueException)
>>>                    continue;
>>>                else
>>>                    throw e;
>>>            }
>>>        }
>>>    };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> David Herman <mailto:dherman at mozilla.com>
>>> January 14, 2012 9:12 AM
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>> Array.prototype.forEach = function(f) {
>>> for (let i = 0, n = this.length; i < n; i++) {
>>> try {
>>> f.call(this, this[i], i);
>>> } catch (e) {
>>> if (e instanceof BreakException)
>>> break;
>>> else if (e instanceof ContinueException)
>>> continue;
>>> else
>>> throw e;
>>> }
>>> }
>>> };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>>
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 13, 2012 9:04 PM
>>> I think it’s a valid concern. The idea is: If I can implement my own 
>>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>>> I also want those loops to have break and continue. You could 
>>> statically determine what construct, say, a break applies to and 
>>> either throw a BreakException (if it applies to a lambda) or 
>>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>>> examples below, when I see a continue, I look for the innermost 
>>> enclosing loop braces and the ones belong to list[i].forEach are 
>>> definitely candidates.
>>> -- 
>>> Dr. Axel Rauschmayer
>>> axel at rauschma.de <mailto:axel at rauschma.de>
>>> home: rauschma.de <http://rauschma.de>
>>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>>> blog: 2ality.com <http://2ality.com>
>>> Brendan Eich <mailto:brendan at mozilla.org>
>>> January 13, 2012 8:54 PM
>>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>>> January 13, 2012 7:29 PM
>>>> Block lambdas have been a hot topic, recently, but there's a point 
>>>> of significant divergence between Ruby (which appears to be the 
>>>> inspiration)
>>>
>>> Not Ruby alone, and not in any chauvinist my-language-is-better 
>>> sense. Smalltalk is the original inspiration for Ruby blocks, and 
>>> the correspondence principle has deep roots.
>>>
>>>> and the proposed solution, in the handling of continue (called 
>>>> 'next', in Ruby) and 'break'.
>>>> To whit: In Ruby, 'next' will end the current run (iteration) of 
>>>> the block, and 'break' will (somehow) terminate the method 
>>>> lexically connected with the block. It can be claimed that this is 
>>>> more intuitive than the current proposal, which aims to make 
>>>> 'break' and 'continue' propagate through block lambdas in the same 
>>>> way 'return' would.
>>>
>>> "Intuitive" depends on intuition, which is not well-defined. Do you 
>>> mean a Rubyist might expect different behavior for break? That is 
>>> possible but JS ain't Ruby and break should not change to do 
>>> something like what it does in Ruby (and we aren't defining a next 
>>> equivalent for JS).
>>>
>>>> Ruby does also support syntactic loops and the same keywords 
>>>> therein and so directly violates Tennent's Correspondence 
>>>> Principle, even though such has been touted as a core reason for 
>>>> the construct. Instead, I believe it reasonable to invoke intuition 
>>>> in this matter. It is intuitive for 'return' to return a value from 
>>>> the lexically enclosing method and it is intuitive for 'continue' 
>>>> to commence the next iteration of the current loop,
>>>
>>> Wait, why do you think break and continue without label operands do 
>>> anything other than break from the nearest enclosing loop (or switch 
>>> or labeled statement if break), or continue the nearest enclosing 
>>> loop? The proposal specifies this.
>>>
>>> function find_odds_in_arrays(list,        // array of arrays
>>>                              skip)        // if found, skip rest
>>> {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === skip) {
>>>         continue;                         // continue the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>> function find_more_odds(list, stop) {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === stop) {
>>>         break;                      // break from the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>>> however that loop is constructed.
>>>
>>> What do you mean by this? The spec talks about nearest enclosing 
>>> loop or relevant control structure in the source code. Are you 
>>> talking about internal loops in implementations (dynamically 
>>> dispatched at that) of methods that take block-lambdas as arguments? 
>>> I.e.
>>>
>>>
>>> function find_first_odd(a) {
>>>   a.forEach { |e, i|
>>>               if (e & 1) return i; }  // returns from function
>>>   return -1;
>>> }
>>>
>>>
>>> The Array.prototype.forEach method's internal implementation is its 
>>> business, and a break instead of the return would be a static error 
>>> in this example. It would not be a dynamic throw-like construct that 
>>> is caught by forEach's implementation.
>>>
>>> /be
>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>> January 13, 2012 7:29 PM
>>> Block lambdas have been a hot topic, recently, but there's a point 
>>> of significant divergence between Ruby (which appears to be the 
>>> inspiration) and the proposed solution, in the handling of continue 
>>> (called 'next', in Ruby) and 'break'.
>>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>>> block, and 'break' will (somehow) terminate the method lexically 
>>> connected with the block. It can be claimed that this is more 
>>> intuitive than the current proposal, which aims to make 'break' and 
>>> 'continue' propagate through block lambdas in the same way 'return' 
>>> would.
>>> Ruby does also support syntactic loops and the same keywords therein 
>>> and so directly violates Tennent's Correspondence Principle, even 
>>> though such has been touted as a core reason for the construct. 
>>> Instead, I believe it reasonable to invoke intuition in this matter. 
>>> It is intuitive for 'return' to return a value from the lexically 
>>> enclosing method and it is intuitive for 'continue' to commence the 
>>> next iteration of the current loop, however that loop is constructed.
>>> Note that the label-based break/continue could still have the 
>>> desired effect, if the proposal was updated to be more like Ruby's 
>>> blocks.
>>> I don't have a strong opinion on the subject, but I hadn't noticed 
>>> the above being discussed, elsewhere, and thought it worth raising. 
>>> If there is a better place for me to raise this, please let me know 
>>> where and accept my apologies.
>>> Regards,
>>> Grant Husbands.
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>
>> ------------------------------------------------------------------------
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 14, 2012 12:51 PM
>>> Herby Vojčík <mailto:herby at mailbox.sk>
>>> January 14, 2012 10:42 AM
>>> === David Herman wrote ===
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>> ===
>>>
>>> What about the exception-less suggestion I put in? It should work in 
>>> any loop construct with lambda-block, even if you must know a little 
>>> about the loop implementation itself. That is, to be able to put:
>>>
>>>    continue |expression|;
>>
>> Who says the block-lambda is being called from a loop at all? Why 
>> should use-cases that want an early result and completion have to use 
>> continue, which is for loops?
>>
>> Worse, this violates TCP. Now you copy and paste this block-lambda 
>> code back into a block statement to refactor the other direction, and 
>> no such "here is the completion value, do not flow past this point in 
>> the block" semantics obtain.
>>>
>>> as a statement in lambda block which instructs the lambda-block 
>>> itself (not the outer function) to return the expression? This is 
>>> the de-facto continue semantics (lambda-block, do return a value and 
>>> the enclosing loop will continue to the next iteration (possibly 
>>> stopping the loop if it chooses not to have more iterations)).
>>
>> No it's not. There is no de-facto continue semantics for 
>> block-lambdas because they haven't been prototyped. For block 
>> statements, no such continue semantics exists.
>>
>>> It is not possible to enforce break in the same manner, but for 
>>> continue, it is possible.
>>
>> It's possible to abuse any existing keyword, but first: why must 
>> there be a new TCP violation? Block-lambda bodies are often 
>> expressions, or if statements, then short/functional-style 
>> statements, not large bodies demonstrating early-normal-completion 
>> opportunities.
>>
>> We should not eliminate TCP violations only to add new ones, 
>> especially without any evidence they're needed and pay their way. 
>> Otherwise we'll get an infinite regress of 
>> TCP-pure-then-add-new-exceptions-and-repeat additions.
>>
>> /be
>>>
>>> Herby
>>>
>>> -----Pôvodná správa----- From: David Herman
>>> Sent: Saturday, January 14, 2012 6:12 PM
>>> To: Axel Rauschmayer
>>> Cc: Brendan Eich ; es-discuss at mozilla.org
>>> Subject: Re: Block Lambdas: break and continue
>>>
>>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>>
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>>    Array.prototype.forEach = function(f) {
>>>        for (let i = 0, n = this.length; i < n; i++) {
>>>            try {
>>>                f.call(this, this[i], i);
>>>            } catch (e) {
>>>                if (e instanceof BreakException)
>>>                    break;
>>>                else if (e instanceof ContinueException)
>>>                    continue;
>>>                else
>>>                    throw e;
>>>            }
>>>        }
>>>    };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> David Herman <mailto:dherman at mozilla.com>
>>> January 14, 2012 9:12 AM
>>>
>>> If I understand your suggestion, you're proposing that non-local 
>>> break and continue should be exposed as standard exceptions, and 
>>> then implementors of loop-like abstractions could choose to catch 
>>> them. E.g. you could implement forEach as:
>>>
>>> Array.prototype.forEach = function(f) {
>>> for (let i = 0, n = this.length; i < n; i++) {
>>> try {
>>> f.call(this, this[i], i);
>>> } catch (e) {
>>> if (e instanceof BreakException)
>>> break;
>>> else if (e instanceof ContinueException)
>>> continue;
>>> else
>>> throw e;
>>> }
>>> }
>>> };
>>>
>>> Whereas a function that does *not* want to expose whether it's using 
>>> loops would simply do nothing with BreakException and 
>>> ContinueException, and they would propagate out and you'd get the 
>>> lexical scoping semantics. Meanwhile, break/continue with an 
>>> explicit target would never be catch-able.
>>>
>>> Did I understand your suggestion correctly?
>>>
>>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>>> enthusiastic about the idea. The semantics is significantly more 
>>> complicated, and it requires you to understand whether a 
>>> higher-order function like forEach is catching these exceptions or 
>>> not. So it becomes an additional part of the API of a function. If 
>>> someone doesn't document what they do with BreakException and 
>>> ContinueException, then writing callbacks you won't actually be able 
>>> to predict what `break` and `continue` will do.
>>>
>>> Dave
>>>
>>>
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 13, 2012 9:04 PM
>>> I think it’s a valid concern. The idea is: If I can implement my own 
>>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>>> I also want those loops to have break and continue. You could 
>>> statically determine what construct, say, a break applies to and 
>>> either throw a BreakException (if it applies to a lambda) or 
>>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>>> examples below, when I see a continue, I look for the innermost 
>>> enclosing loop braces and the ones belong to list[i].forEach are 
>>> definitely candidates.
>>>
>>>
>>>
>>> -- 
>>> Dr. Axel Rauschmayer
>>> axel at rauschma.de <mailto:axel at rauschma.de>
>>>
>>> home: rauschma.de <http://rauschma.de>
>>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>>> blog: 2ality.com <http://2ality.com>
>>>
>>> Brendan Eich <mailto:brendan at mozilla.org>
>>> January 13, 2012 8:54 PM
>>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>>> January 13, 2012 7:29 PM
>>>> Block lambdas have been a hot topic, recently, but there's a point 
>>>> of significant divergence between Ruby (which appears to be the 
>>>> inspiration)
>>>
>>> Not Ruby alone, and not in any chauvinist my-language-is-better 
>>> sense. Smalltalk is the original inspiration for Ruby blocks, and 
>>> the correspondence principle has deep roots.
>>>
>>>> and the proposed solution, in the handling of continue (called 
>>>> 'next', in Ruby) and 'break'.
>>>>
>>>> To whit: In Ruby, 'next' will end the current run (iteration) of 
>>>> the block, and 'break' will (somehow) terminate the method 
>>>> lexically connected with the block. It can be claimed that this is 
>>>> more intuitive than the current proposal, which aims to make 
>>>> 'break' and 'continue' propagate through block lambdas in the same 
>>>> way 'return' would.
>>>
>>> "Intuitive" depends on intuition, which is not well-defined. Do you 
>>> mean a Rubyist might expect different behavior for break? That is 
>>> possible but JS ain't Ruby and break should not change to do 
>>> something like what it does in Ruby (and we aren't defining a next 
>>> equivalent for JS).
>>>
>>>> Ruby does also support syntactic loops and the same keywords 
>>>> therein and so directly violates Tennent's Correspondence 
>>>> Principle, even though such has been touted as a core reason for 
>>>> the construct. Instead, I believe it reasonable to invoke intuition 
>>>> in this matter. It is intuitive for 'return' to return a value from 
>>>> the lexically enclosing method and it is intuitive for 'continue' 
>>>> to commence the next iteration of the current loop,
>>>
>>> Wait, why do you think break and continue without label operands do 
>>> anything other than break from the nearest enclosing loop (or switch 
>>> or labeled statement if break), or continue the nearest enclosing 
>>> loop? The proposal specifies this.
>>>
>>> function find_odds_in_arrays(list,        // array of arrays
>>>                              skip)        // if found, skip rest
>>> {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === skip) {
>>>         continue;                         // continue the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>> function find_more_odds(list, stop) {
>>>   let a = [];
>>>   for (let i = 0; i < list.length; i++) {
>>>     list[i].forEach {
>>>       |e|
>>>       if (e === stop) {
>>>         break;                      // break from the for loop
>>>       }
>>>       if (e & 1) {
>>>         a.push(e);
>>>       }
>>>     }
>>>   }
>>>   return a;
>>> }
>>>
>>>> however that loop is constructed.
>>>
>>> What do you mean by this? The spec talks about nearest enclosing 
>>> loop or relevant control structure in the source code. Are you 
>>> talking about internal loops in implementations (dynamically 
>>> dispatched at that) of methods that take block-lambdas as arguments? 
>>> I.e.
>>>
>>>
>>> function find_first_odd(a) {
>>>   a.forEach { |e, i|
>>>               if (e & 1) return i; }  // returns from function
>>>   return -1;
>>> }
>>>
>>>
>>> The Array.prototype.forEach method's internal implementation is its 
>>> business, and a break instead of the return would be a static error 
>>> in this example. It would not be a dynamic throw-like construct that 
>>> is caught by forEach's implementation.
>>>
>>> /be
>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>> January 13, 2012 7:29 PM
>>> Block lambdas have been a hot topic, recently, but there's a point 
>>> of significant divergence between Ruby (which appears to be the 
>>> inspiration) and the proposed solution, in the handling of continue 
>>> (called 'next', in Ruby) and 'break'.
>>>
>>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>>> block, and 'break' will (somehow) terminate the method lexically 
>>> connected with the block. It can be claimed that this is more 
>>> intuitive than the current proposal, which aims to make 'break' and 
>>> 'continue' propagate through block lambdas in the same way 'return' 
>>> would.
>>>
>>> Ruby does also support syntactic loops and the same keywords therein 
>>> and so directly violates Tennent's Correspondence Principle, even 
>>> though such has been touted as a core reason for the construct. 
>>> Instead, I believe it reasonable to invoke intuition in this matter. 
>>> It is intuitive for 'return' to return a value from the lexically 
>>> enclosing method and it is intuitive for 'continue' to commence the 
>>> next iteration of the current loop, however that loop is constructed.
>>>
>>> Note that the label-based break/continue could still have the 
>>> desired effect, if the proposal was updated to be more like Ruby's 
>>> blocks.
>>>
>>> I don't have a strong opinion on the subject, but I hadn't noticed 
>>> the above being discussed, elsewhere, and thought it worth raising. 
>>> If there is a better place for me to raise this, please let me know 
>>> where and accept my apologies.
>>>
>>> Regards,
>>> Grant Husbands.
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>> Herby Vojčík <mailto:herby at mailbox.sk>
>> January 14, 2012 10:42 AM
>> === David Herman wrote ===
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>> ===
>>
>> What about the exception-less suggestion I put in? It should work in 
>> any loop construct with lambda-block, even if you must know a little 
>> about the loop implementation itself. That is, to be able to put:
>>
>>    continue |expression|;
>>
>> as a statement in lambda block which instructs the lambda-block 
>> itself (not the outer function) to return the expression? This is the 
>> de-facto continue semantics (lambda-block, do return a value and the 
>> enclosing loop will continue to the next iteration (possibly stopping 
>> the loop if it chooses not to have more iterations)). It is not 
>> possible to enforce break in the same manner, but for continue, it is 
>> possible.
>>
>> Herby
>>
>> -----Pôvodná správa----- From: David Herman
>> Sent: Saturday, January 14, 2012 6:12 PM
>> To: Axel Rauschmayer
>> Cc: Brendan Eich ; es-discuss at mozilla.org
>> Subject: Re: Block Lambdas: break and continue
>>
>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>>    Array.prototype.forEach = function(f) {
>>        for (let i = 0, n = this.length; i < n; i++) {
>>            try {
>>                f.call(this, this[i], i);
>>            } catch (e) {
>>                if (e instanceof BreakException)
>>                    break;
>>                else if (e instanceof ContinueException)
>>                    continue;
>>                else
>>                    throw e;
>>            }
>>        }
>>    };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>> David Herman <mailto:dherman at mozilla.com>
>> January 14, 2012 9:12 AM
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>> Array.prototype.forEach = function(f) {
>> for (let i = 0, n = this.length; i < n; i++) {
>> try {
>> f.call(this, this[i], i);
>> } catch (e) {
>> if (e instanceof BreakException)
>> break;
>> else if (e instanceof ContinueException)
>> continue;
>> else
>> throw e;
>> }
>> }
>> };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>>
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 13, 2012 9:04 PM
>> I think it’s a valid concern. The idea is: If I can implement my own 
>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>> I also want those loops to have break and continue. You could 
>> statically determine what construct, say, a break applies to and 
>> either throw a BreakException (if it applies to a lambda) or 
>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>> examples below, when I see a continue, I look for the innermost 
>> enclosing loop braces and the ones belong to list[i].forEach are 
>> definitely candidates.
>>
>>
>>
>> -- 
>> Dr. Axel Rauschmayer
>> axel at rauschma.de <mailto:axel at rauschma.de>
>>
>> home: rauschma.de <http://rauschma.de>
>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>> blog: 2ality.com <http://2ality.com>
>>
> Brendan Eich <mailto:brendan at mozilla.org>
> January 14, 2012 12:51 PM
>> Herby Vojčík <mailto:herby at mailbox.sk>
>> January 14, 2012 10:42 AM
>> === David Herman wrote ===
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>> ===
>>
>> What about the exception-less suggestion I put in? It should work in 
>> any loop construct with lambda-block, even if you must know a little 
>> about the loop implementation itself. That is, to be able to put:
>>
>>    continue |expression|;
>
> Who says the block-lambda is being called from a loop at all? Why 
> should use-cases that want an early result and completion have to use 
> continue, which is for loops?
>
> Worse, this violates TCP. Now you copy and paste this block-lambda 
> code back into a block statement to refactor the other direction, and 
> no such "here is the completion value, do not flow past this point in 
> the block" semantics obtain.
>>
>> as a statement in lambda block which instructs the lambda-block 
>> itself (not the outer function) to return the expression? This is the 
>> de-facto continue semantics (lambda-block, do return a value and the 
>> enclosing loop will continue to the next iteration (possibly stopping 
>> the loop if it chooses not to have more iterations)).
>
> No it's not. There is no de-facto continue semantics for block-lambdas 
> because they haven't been prototyped. For block statements, no such 
> continue semantics exists.
>
>> It is not possible to enforce break in the same manner, but for 
>> continue, it is possible.
>
> It's possible to abuse any existing keyword, but first: why must there 
> be a new TCP violation? Block-lambda bodies are often expressions, or 
> if statements, then short/functional-style statements, not large 
> bodies demonstrating early-normal-completion opportunities.
>
> We should not eliminate TCP violations only to add new ones, 
> especially without any evidence they're needed and pay their way. 
> Otherwise we'll get an infinite regress of 
> TCP-pure-then-add-new-exceptions-and-repeat additions.
>
> /be
>>
>> Herby
>>
>> -----Pôvodná správa----- From: David Herman
>> Sent: Saturday, January 14, 2012 6:12 PM
>> To: Axel Rauschmayer
>> Cc: Brendan Eich ; es-discuss at mozilla.org
>> Subject: Re: Block Lambdas: break and continue
>>
>> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>>
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>>    Array.prototype.forEach = function(f) {
>>        for (let i = 0, n = this.length; i < n; i++) {
>>            try {
>>                f.call(this, this[i], i);
>>            } catch (e) {
>>                if (e instanceof BreakException)
>>                    break;
>>                else if (e instanceof ContinueException)
>>                    continue;
>>                else
>>                    throw e;
>>            }
>>        }
>>    };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> David Herman <mailto:dherman at mozilla.com>
>> January 14, 2012 9:12 AM
>>
>> If I understand your suggestion, you're proposing that non-local 
>> break and continue should be exposed as standard exceptions, and then 
>> implementors of loop-like abstractions could choose to catch them. 
>> E.g. you could implement forEach as:
>>
>> Array.prototype.forEach = function(f) {
>> for (let i = 0, n = this.length; i < n; i++) {
>> try {
>> f.call(this, this[i], i);
>> } catch (e) {
>> if (e instanceof BreakException)
>> break;
>> else if (e instanceof ContinueException)
>> continue;
>> else
>> throw e;
>> }
>> }
>> };
>>
>> Whereas a function that does *not* want to expose whether it's using 
>> loops would simply do nothing with BreakException and 
>> ContinueException, and they would propagate out and you'd get the 
>> lexical scoping semantics. Meanwhile, break/continue with an explicit 
>> target would never be catch-able.
>>
>> Did I understand your suggestion correctly?
>>
>> This *may* not violate TCP (I'm not quite sure), but I'm not 
>> enthusiastic about the idea. The semantics is significantly more 
>> complicated, and it requires you to understand whether a higher-order 
>> function like forEach is catching these exceptions or not. So it 
>> becomes an additional part of the API of a function. If someone 
>> doesn't document what they do with BreakException and 
>> ContinueException, then writing callbacks you won't actually be able 
>> to predict what `break` and `continue` will do.
>>
>> Dave
>>
>>
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 13, 2012 9:04 PM
>> I think it’s a valid concern. The idea is: If I can implement my own 
>> loops (the nice-looking paren-free syntax feeds that illusion!) then 
>> I also want those loops to have break and continue. You could 
>> statically determine what construct, say, a break applies to and 
>> either throw a BreakException (if it applies to a lambda) or 
>> TCP-break (if it applies to an enclosing non-lambda loop). In the 
>> examples below, when I see a continue, I look for the innermost 
>> enclosing loop braces and the ones belong to list[i].forEach are 
>> definitely candidates.
>>
>>
>>
>> -- 
>> Dr. Axel Rauschmayer
>> axel at rauschma.de <mailto:axel at rauschma.de>
>>
>> home: rauschma.de <http://rauschma.de>
>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>> blog: 2ality.com <http://2ality.com>
>>
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 13, 2012 8:54 PM
>>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>>> January 13, 2012 7:29 PM
>>> Block lambdas have been a hot topic, recently, but there's a point 
>>> of significant divergence between Ruby (which appears to be the 
>>> inspiration)
>>
>> Not Ruby alone, and not in any chauvinist my-language-is-better 
>> sense. Smalltalk is the original inspiration for Ruby blocks, and the 
>> correspondence principle has deep roots.
>>
>>> and the proposed solution, in the handling of continue (called 
>>> 'next', in Ruby) and 'break'.
>>>
>>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>>> block, and 'break' will (somehow) terminate the method lexically 
>>> connected with the block. It can be claimed that this is more 
>>> intuitive than the current proposal, which aims to make 'break' and 
>>> 'continue' propagate through block lambdas in the same way 'return' 
>>> would.
>>
>> "Intuitive" depends on intuition, which is not well-defined. Do you 
>> mean a Rubyist might expect different behavior for break? That is 
>> possible but JS ain't Ruby and break should not change to do 
>> something like what it does in Ruby (and we aren't defining a next 
>> equivalent for JS).
>>
>>> Ruby does also support syntactic loops and the same keywords therein 
>>> and so directly violates Tennent's Correspondence Principle, even 
>>> though such has been touted as a core reason for the construct. 
>>> Instead, I believe it reasonable to invoke intuition in this matter. 
>>> It is intuitive for 'return' to return a value from the lexically 
>>> enclosing method and it is intuitive for 'continue' to commence the 
>>> next iteration of the current loop,
>>
>> Wait, why do you think break and continue without label operands do 
>> anything other than break from the nearest enclosing loop (or switch 
>> or labeled statement if break), or continue the nearest enclosing 
>> loop? The proposal specifies this.
>>
>> function find_odds_in_arrays(list,        // array of arrays
>>                              skip)        // if found, skip rest
>> {
>>   let a = [];
>>   for (let i = 0; i < list.length; i++) {
>>     list[i].forEach {
>>       |e|
>>       if (e === skip) {
>>         continue;                         // continue the for loop
>>       }
>>       if (e & 1) {
>>         a.push(e);
>>       }
>>     }
>>   }
>>   return a;
>> }
>>
>> function find_more_odds(list, stop) {
>>   let a = [];
>>   for (let i = 0; i < list.length; i++) {
>>     list[i].forEach {
>>       |e|
>>       if (e === stop) {
>>         break;                      // break from the for loop
>>       }
>>       if (e & 1) {
>>         a.push(e);
>>       }
>>     }
>>   }
>>   return a;
>> }
>>
>>> however that loop is constructed.
>>
>> What do you mean by this? The spec talks about nearest enclosing loop 
>> or relevant control structure in the source code. Are you talking 
>> about internal loops in implementations (dynamically dispatched at 
>> that) of methods that take block-lambdas as arguments? I.e.
>>
>>
>> function find_first_odd(a) {
>>   a.forEach { |e, i|
>>               if (e & 1) return i; }  // returns from function
>>   return -1;
>> }
>>
>>
>> The Array.prototype.forEach method's internal implementation is its 
>> business, and a break instead of the return would be a static error 
>> in this example. It would not be a dynamic throw-like construct that 
>> is caught by forEach's implementation.
>>
>> /be
>> Grant Husbands <mailto:esdiscuss at grant.x43.net>
>> January 13, 2012 7:29 PM
>> Block lambdas have been a hot topic, recently, but there's a point of 
>> significant divergence between Ruby (which appears to be the 
>> inspiration) and the proposed solution, in the handling of continue 
>> (called 'next', in Ruby) and 'break'.
>>
>> To whit: In Ruby, 'next' will end the current run (iteration) of the 
>> block, and 'break' will (somehow) terminate the method lexically 
>> connected with the block. It can be claimed that this is more 
>> intuitive than the current proposal, which aims to make 'break' and 
>> 'continue' propagate through block lambdas in the same way 'return' 
>> would.
>>
>> Ruby does also support syntactic loops and the same keywords therein 
>> and so directly violates Tennent's Correspondence Principle, even 
>> though such has been touted as a core reason for the construct. 
>> Instead, I believe it reasonable to invoke intuition in this matter. 
>> It is intuitive for 'return' to return a value from the lexically 
>> enclosing method and it is intuitive for 'continue' to commence the 
>> next iteration of the current loop, however that loop is constructed.
>>
>> Note that the label-based break/continue could still have the desired 
>> effect, if the proposal was updated to be more like Ruby's blocks.
>>
>> I don't have a strong opinion on the subject, but I hadn't noticed 
>> the above being discussed, elsewhere, and thought it worth raising. 
>> If there is a better place for me to raise this, please let me know 
>> where and accept my apologies.
>>
>> Regards,
>> Grant Husbands.
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
> Herby Vojčík <mailto:herby at mailbox.sk>
> January 14, 2012 10:42 AM
> === David Herman wrote ===
> This *may* not violate TCP (I'm not quite sure), but I'm not 
> enthusiastic about the idea. The semantics is significantly more 
> complicated, and it requires you to understand whether a higher-order 
> function like forEach is catching these exceptions or not. So it 
> becomes an additional part of the API of a function. If someone 
> doesn't document what they do with BreakException and 
> ContinueException, then writing callbacks you won't actually be able 
> to predict what `break` and `continue` will do.
> ===
>
> What about the exception-less suggestion I put in? It should work in 
> any loop construct with lambda-block, even if you must know a little 
> about the loop implementation itself. That is, to be able to put:
>
>    continue |expression|;
>
> as a statement in lambda block which instructs the lambda-block itself 
> (not the outer function) to return the expression? This is the 
> de-facto continue semantics (lambda-block, do return a value and the 
> enclosing loop will continue to the next iteration (possibly stopping 
> the loop if it chooses not to have more iterations)). It is not 
> possible to enforce break in the same manner, but for continue, it is 
> possible.
>
> Herby
>
> -----Pôvodná správa----- From: David Herman
> Sent: Saturday, January 14, 2012 6:12 PM
> To: Axel Rauschmayer
> Cc: Brendan Eich ; es-discuss at mozilla.org
> Subject: Re: Block Lambdas: break and continue
>
> On Jan 13, 2012, at 9:04 PM, Axel Rauschmayer wrote:
>
>
> If I understand your suggestion, you're proposing that non-local break 
> and continue should be exposed as standard exceptions, and then 
> implementors of loop-like abstractions could choose to catch them. 
> E.g. you could implement forEach as:
>
>    Array.prototype.forEach = function(f) {
>        for (let i = 0, n = this.length; i < n; i++) {
>            try {
>                f.call(this, this[i], i);
>            } catch (e) {
>                if (e instanceof BreakException)
>                    break;
>                else if (e instanceof ContinueException)
>                    continue;
>                else
>                    throw e;
>            }
>        }
>    };
>
> Whereas a function that does *not* want to expose whether it's using 
> loops would simply do nothing with BreakException and 
> ContinueException, and they would propagate out and you'd get the 
> lexical scoping semantics. Meanwhile, break/continue with an explicit 
> target would never be catch-able.
>
> Did I understand your suggestion correctly?
>
> This *may* not violate TCP (I'm not quite sure), but I'm not 
> enthusiastic about the idea. The semantics is significantly more 
> complicated, and it requires you to understand whether a higher-order 
> function like forEach is catching these exceptions or not. So it 
> becomes an additional part of the API of a function. If someone 
> doesn't document what they do with BreakException and 
> ContinueException, then writing callbacks you won't actually be able 
> to predict what `break` and `continue` will do.
>
> Dave
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
> David Herman <mailto:dherman at mozilla.com>
> January 14, 2012 9:12 AM
>
> If I understand your suggestion, you're proposing that non-local break 
> and continue should be exposed as standard exceptions, and then 
> implementors of loop-like abstractions could choose to catch them. 
> E.g. you could implement forEach as:
>
> Array.prototype.forEach = function(f) {
> for (let i = 0, n = this.length; i < n; i++) {
> try {
> f.call(this, this[i], i);
> } catch (e) {
> if (e instanceof BreakException)
> break;
> else if (e instanceof ContinueException)
> continue;
> else
> throw e;
> }
> }
> };
>
> Whereas a function that does *not* want to expose whether it's using 
> loops would simply do nothing with BreakException and 
> ContinueException, and they would propagate out and you'd get the 
> lexical scoping semantics. Meanwhile, break/continue with an explicit 
> target would never be catch-able.
>
> Did I understand your suggestion correctly?
>
> This *may* not violate TCP (I'm not quite sure), but I'm not 
> enthusiastic about the idea. The semantics is significantly more 
> complicated, and it requires you to understand whether a higher-order 
> function like forEach is catching these exceptions or not. So it 
> becomes an additional part of the API of a function. If someone 
> doesn't document what they do with BreakException and 
> ContinueException, then writing callbacks you won't actually be able 
> to predict what `break` and `continue` will do.
>
> Dave
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1327 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0006.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1080 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0007.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1254 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0008.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1222 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0009.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1290 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0010.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: compose-unknown-contact.jpg
Type: image/jpeg
Size: 770 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/30d81e38/attachment-0011.jpg>


More information about the es-discuss mailing list