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