Block Lambdas: break and continue

Brendan Eich brendan at mozilla.org
Fri Jan 13 20:54:04 PST 2012


> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120113/65da20bf/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/20120113/65da20bf/attachment-0001.jpg>


More information about the es-discuss mailing list