Block Lambdas: break and continue

Herby Vojčík herby at mailbox.sk
Sat Jan 14 02:33:09 PST 2012


Hello,

I think it is a concern, too, but from other point of view. By lambdaing the 
block, we got an added value of TCP (that is, "return" return from outer 
function) but we lost the ability of the lambda block to early local return 
the value itself.

Take example of forEach: it has no possibility of break; but it has 
possibility of continue - early local return from the block
Take example of some: it has possibility of break - early local return of 
falsy value; it has possibility of continue - early local return of truy 
value

One answer to this is "multiline lambdas are not Pythonic", but I think this 
is not the right answer, lambda blocks are inspired by Smalltalk, in which 
multiline blocks are normal. Correct me if I am wrong and this _is_ in fact 
the answer.

The second answer should be to somehow allow to early local return a value 
from the lambda block itself. Since early local return are often used in 
loops to perform "break" or "continue" functionality, I'd suggest to allow
    break (Expression)
and
    continue (Expression)
and have them doing the same effect, that is, to return the value of 
expression from the lambda block itself. It is up to user which one to use 
based on which is more intent revealing per each use.

Herby

-----Pôvodná správa----- 
From: Axel Rauschmayer
Sent: Saturday, January 14, 2012 6:04 AM
To: Brendan Eich
Cc: es-discuss at mozilla.org
Subject: Re: Block Lambdas: break and continue

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.


On Jan 14, 2012, at 5:54 , Brendan Eich wrote:




Grant Husbands
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
_______________________________________________
es-discuss mailing list
es-discuss at mozilla.org
https://mail.mozilla.org/listinfo/es-discuss



















-- 
Dr. Axel Rauschmayer
axel at rauschma.de

home: rauschma.de
twitter: twitter.com/rauschma
blog: 2ality.com






















_______________________________________________
es-discuss mailing list
es-discuss at mozilla.org
https://mail.mozilla.org/listinfo/es-discuss 



More information about the es-discuss mailing list