Block Lambdas: break and continue

Brendan Eich brendan at mozilla.org
Sat Jan 14 15:02:25 PST 2012


> Grant Husbands <mailto:esdiscuss at grant.x43.net>
> January 14, 2012 2:51 PM
>
> I agree that exceptions might not be the way to handle it. I've seen
> it noted that something like these would work under the existing
> proposal:
>
> forEach(arr) { |a|
> skip: {
> // ...
> if (...) break skip; // Equivalent to continue
> }
> };
>
> end: forEach(arr) { |s|
> // ...
> if (...) break end; // Equivalent to break
> };

Yes (just to confirm), these work in the strawman today. But (in case 
there's confusion; signs of it on twitter and here) one doesn't need 
labels to break from a true loop/switch or continue a true loop. This is 
only the forEach (and similar) case.
>
> The mechanism by which they work may give a more agreeable path for
> implementation of the new kind of end/break, perhaps along with a
> keyword near the forEach to enable the behaviour.

Right, Axel's "for " prefix from several messages back:

     for mycollection.each({ | x | if (x === 0) break })


That is an interesting idea, I meant to reply to it.

Of course we want to uphold TCP, which constrains the design. What works 
here must work in a regular block statement as body of such a loopish 
structure.

> It would also mean
> that break/continue could still be matched with their jump-sites at
> compile time. There'd be the caveat that the iterating function would
> have no control over that flow, but that is already the case for
> continue/break/return under the existing proposal.

Yes, and that is the flip side of the win of avoiding reified break and 
continue exceptions: you can't handle them, so you don't have to handle 
them (or worry about it).
>
> To try to be clear, I'm implying a syntax akin to this could give the
> desired break/continue functionality for lambda-block-based loops, and
> could essentially desugar to the above:
> for forEach(arr) { |a|
> // ...
> if (...) continue;
> if (...) break;
> };
>
> It would probably need alteration to not conflict with other recent 
> syntax.

It's ok as a statement extension since for currently must be followed by 
( in statement contex. The paren-free for/of comprehension and generator 
expression forms would be problematic if we wanted such an extension for 
them, but we do not.

However, paren-free as a relaxation of syntax, as I've proposed and am 
still working on in the background, would have a problem with this for 
helper {|x| ...} idea. More when I reply to Axel in a bit.

/be

>
> Regards,
> Grant Husbands.
> _______________________________________________
> 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:31 PM
>
> And then only near or at a top-level event loop.
>
> Exception handling is the issue here, because of the proposal to add 
> reifed break and continue as thrown exceptions. How exception handling 
> is practiced (usually not) is highly relevant.
>
> Wishing for JS users to happily add more exception handling won't make 
> that work happen, because it costs a lot. That it costs a lot (too 
> much in my view) is enough to consider not adding new exceptions that 
> must be considered when designing all "looping" and "wrapping" (AOP) APis.
>
> /be
> Brendan Eich <mailto:brendan at mozilla.org>
> January 14, 2012 1:24 PM
>> François REMY <mailto:fremycompany_pub at yahoo.fr>
>> January 14, 2012 1:14 PM
>> What you said about 'large-scale' try/catch seems irrevelant to me.
>
> Not at all, since you among others are proposing break and continue 
> exceptions (whether thrown explicitly via new syntax, or implicitly by 
> break and continue statements). This as Allen's examples showed 
> requires scaling across more than one activation, and across dynamic 
> dispatch (no static-only break or continue as in the strawman).
>
>> If you make a function that takes a callback as an argument, you 
>> already HAVE to use a try-catch,
>
> Not so. First, real code does not use try/catch in such callback 
> calling functions at all. The Array extras do not try/catch, whether 
> they are implemented in JS or some host VM implementation language 
> (usually C++). Exceptions propagate and unwind without any 
> try-guarding or catch/finally handling.
>
>> since you have to prevent any faillure in the code of the callback 
>> since you can't trust it, even if he's empty (as you noted).
>
> I noted no such thing.
>
>> So, the BreakException has no chance to go outside the function who 
>> called the block lambda.
>
> The problem is that all callback-calling functions that "loop" 
> (however defined) must now try/catch, where before they did not. Yes, 
> there is a benefit: in your proposal one can "throw break" or "throw 
> continue" from a block-lambda provided as the callback, *if* one knows 
> the API well and is sure of which calling function was dispatched 
> dynamically.
>
> For other functions, and when composing deeper callstacks (as in 
> Allen's logging example), then one has to think about whether to try 
> or not. It may be that the thrown break or continue can propagate 
> without handling, but if the intervening function is in a loop, then 
> not so: that function must try and rethrow in its catch clause, in 
> order to get the "throw break" to reach the grand-caller of the 
> block-lambda. This is an onerous requirement in the limit!
>
>> If you want to implement a function that loops, you just need to add 
>> some code to handle BreakException and ContinueException.
>
> Yes, but handle how? This is a new and harsh requirement. 
> Callback-calling (downward-funarg calling, let's say) functions 
> written yesterday and today simply do *not* try/catch because a 
> callback might throw. Exception handling is seldom used in the large 
> except to void the exception.
>
> /be
>> If you don't want, you just don't use it. It's up to you.
>> *From:* Brendan Eich <mailto:brendan at mozilla.org>
>> *Sent:* Saturday, January 14, 2012 10:00 PM
>> *To:* Axel Rauschmayer <mailto:axel at rauschma.de>
>> *Cc:* es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>> *Subject:* Re: Block Lambdas: break and continue
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 14, 2012 12:35 PM
>>> 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.
>>
>> See Allen's post for how this does not compose well.
>>> I don't think it's a must-have, but whenever you catch exceptions, 
>>> you have similar issues.
>>
>> Sorry, termination style exception handling is pretty much a failure 
>> outside of local protocols with automated catching (for/of in Harmony 
>> loops, comprehensions, and generator expressions).
>>
>> People build local ad-hoc try/catch machines, e.g. for generator 
>> schedulers, and those can be managed even without syntax, but these 
>> "kernels" require expertise and careful API design.
>>
>> But in general when you see a try/catch, the catch is empty and the 
>> try is because of a call out of module or ownable unit of code, into 
>> some hostile subsystem or "other" that has in the past thrown a 
>> random exception.
>>
>> IOW, termination-style exception handling does not scale. It's also a 
>> dynamic thing, like magic return codes. Intervening functions on the 
>> call stack with no necessary static relation to one another may have 
>> to try and catch (or at least try and finally) to unwind-protect. Not 
>> for memory management, of course, but for other mandatory protocols 
>> such as RAII patterns.
>>
>> So I'm against adding BreakException and ContinueException and 
>> defining block-lambda break and continue in terms of throw. As Dave 
>> and Allen argued, this enlarges the contract of every possible 
>> intervening function to include exceptions. Exceptions are usually 
>> ignored at high level, used only locally (across shallow continuation 
>> calls).
>>
>> We should avoid adding dependencies on exceptions that must be 
>> managed by arbitrarily large codebases and arbitrarily deep callstacks.
>>
>> /be
>>> -- 
>>> 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
>>> 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
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 14, 2012 1:00 PM
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 14, 2012 12:35 PM
>>>
>>> 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.
>>
>> See Allen's post for how this does not compose well.
>>>
>>> I don't think it's a must-have, but whenever you catch exceptions, 
>>> you have similar issues.
>>
>> Sorry, termination style exception handling is pretty much a failure 
>> outside of local protocols with automated catching (for/of in Harmony 
>> loops, comprehensions, and generator expressions).
>>
>> People build local ad-hoc try/catch machines, e.g. for generator 
>> schedulers, and those can be managed even without syntax, but these 
>> "kernels" require expertise and careful API design.
>>
>> But in general when you see a try/catch, the catch is empty and the 
>> try is because of a call out of module or ownable unit of code, into 
>> some hostile subsystem or "other" that has in the past thrown a 
>> random exception.
>>
>> IOW, termination-style exception handling does not scale. It's also a 
>> dynamic thing, like magic return codes. Intervening functions on the 
>> call stack with no necessary static relation to one another may have 
>> to try and catch (or at least try and finally) to unwind-protect. Not 
>> for memory management, of course, but for other mandatory protocols 
>> such as RAII patterns.
>>
>> So I'm against adding BreakException and ContinueException and 
>> defining block-lambda break and continue in terms of throw. As Dave 
>> and Allen argued, this enlarges the contract of every possible 
>> intervening function to include exceptions. Exceptions are usually 
>> ignored at high level, used only locally (across shallow continuation 
>> calls).
>>
>> We should avoid adding dependencies on exceptions that must be 
>> managed by arbitrarily large codebases and arbitrarily deep callstacks.
>>
>> /be
>>>
>>> -- 
>>> 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
>>> 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
>> 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
> François REMY <mailto:fremycompany_pub at yahoo.fr>
> January 14, 2012 1:14 PM
> What you said about 'large-scale' try/catch seems irrevelant to me. If 
> you make a function that takes a callback as an argument, you already 
> HAVE to use a try-catch, since you have to prevent any faillure in the 
> code of the callback since you can't trust it, even if he's empty (as 
> you noted). So, the BreakException has no chance to go outside the 
> function who called the block lambda.
> If you want to implement a function that loops, you just need to add 
> some code to handle BreakException and ContinueException. If you don't 
> want, you just don't use it. It's up to you.
> *From:* Brendan Eich <mailto:brendan at mozilla.org>
> *Sent:* Saturday, January 14, 2012 10:00 PM
> *To:* Axel Rauschmayer <mailto:axel at rauschma.de>
> *Cc:* es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> *Subject:* Re: Block Lambdas: break and continue
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 14, 2012 12:35 PM
>> 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.
>
> See Allen's post for how this does not compose well.
>> I don't think it's a must-have, but whenever you catch exceptions, 
>> you have similar issues.
>
> Sorry, termination style exception handling is pretty much a failure 
> outside of local protocols with automated catching (for/of in Harmony 
> loops, comprehensions, and generator expressions).
>
> People build local ad-hoc try/catch machines, e.g. for generator 
> schedulers, and those can be managed even without syntax, but these 
> "kernels" require expertise and careful API design.
>
> But in general when you see a try/catch, the catch is empty and the 
> try is because of a call out of module or ownable unit of code, into 
> some hostile subsystem or "other" that has in the past thrown a random 
> exception.
>
> IOW, termination-style exception handling does not scale. It's also a 
> dynamic thing, like magic return codes. Intervening functions on the 
> call stack with no necessary static relation to one another may have 
> to try and catch (or at least try and finally) to unwind-protect. Not 
> for memory management, of course, but for other mandatory protocols 
> such as RAII patterns.
>
> So I'm against adding BreakException and ContinueException and 
> defining block-lambda break and continue in terms of throw. As Dave 
> and Allen argued, this enlarges the contract of every possible 
> intervening function to include exceptions. Exceptions are usually 
> ignored at high level, used only locally (across shallow continuation 
> calls).
>
> We should avoid adding dependencies on exceptions that must be managed 
> by arbitrarily large codebases and arbitrarily deep callstacks.
>
> /be
>> -- 
>> 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
>> 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
> Brendan Eich <mailto:brendan at mozilla.org>
> January 14, 2012 1:00 PM
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 14, 2012 12:35 PM
>>
>> 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.
>
> See Allen's post for how this does not compose well.
>>
>> I don't think it's a must-have, but whenever you catch exceptions, 
>> you have similar issues.
>
> Sorry, termination style exception handling is pretty much a failure 
> outside of local protocols with automated catching (for/of in Harmony 
> loops, comprehensions, and generator expressions).
>
> People build local ad-hoc try/catch machines, e.g. for generator 
> schedulers, and those can be managed even without syntax, but these 
> "kernels" require expertise and careful API design.
>
> But in general when you see a try/catch, the catch is empty and the 
> try is because of a call out of module or ownable unit of code, into 
> some hostile subsystem or "other" that has in the past thrown a random 
> exception.
>
> IOW, termination-style exception handling does not scale. It's also a 
> dynamic thing, like magic return codes. Intervening functions on the 
> call stack with no necessary static relation to one another may have 
> to try and catch (or at least try and finally) to unwind-protect. Not 
> for memory management, of course, but for other mandatory protocols 
> such as RAII patterns.
>
> So I'm against adding BreakException and ContinueException and 
> defining block-lambda break and continue in terms of throw. As Dave 
> and Allen argued, this enlarges the contract of every possible 
> intervening function to include exceptions. Exceptions are usually 
> ignored at high level, used only locally (across shallow continuation 
> calls).
>
> We should avoid adding dependencies on exceptions that must be managed 
> by arbitrarily large codebases and arbitrarily deep callstacks.
>
> /be
>>
>> -- 
>> 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
>> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/639e8a59/attachment-0001.html>
-------------- 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/639e8a59/attachment-0005.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/639e8a59/attachment-0006.jpg>
-------------- 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/639e8a59/attachment-0007.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/639e8a59/attachment-0008.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/639e8a59/attachment-0009.jpg>


More information about the es-discuss mailing list