Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Jon Zeppieri
On Mon, Oct 13, 2008 at 10:48 PM, Mark S. Miller [EMAIL PROTECTED] wrote:
 On Mon, Oct 13, 2008 at 5:00 PM, Jon Zeppieri [EMAIL PROTECTED] wrote:
 I'm talking about a rewrite from 'for' to
 'lambda' that satisfies the following properties:

 1) for (var i = 0; i  len; i++) ... continues to mean what it means in ES3.
 2) for (let i = 0; i  len; i++) ... has the proper scope for 'i'
 (which you reiterated above), *and* 'i' is rebound -- not mutated --
 on each iteration.
 3) The rewrite rules are the *same,* regardless of whether it's a for
 (var ...) or a for (let ...) loop.

 At least, that's what I took Mark to mean.  He can correct me if I'm wrong.


 You're right. However, the desugaring is more complex than I expected.
 Thanks for asking me to write it down.

  for (keyword varName = initExpr; testExpr; updateExpr) { body }

 desugars to (hygienic  renaming aside):

 breakTarget: {
  const loop = lambda(iter = initExpr) {
keyword varName = iter;
if (! testExpr) { break breakTarget; }
continueTarget: { body }
lambda(iter2 = varName) {
  keyword varName = iter2;
  updateExpr;
  loop(varName);
}();
  };
  loop();
 }

 I believe this meets all your requirements.

I believe it does.  Very cool.  It won't handle the fully general
for(;;).  E.g.,

for (let fn = lambda(n) { ... fn(...) ... }; testExpr; updateExpr) ...

Also,

for (let i = 0, j = i + 1; ...) ...

But the modifications needed to make these work are pretty straightforward.


Then again, I'm not sure it matters.  I think the real problem here is
that the updateExpr, as written by the user, is (or, rather, usually
is) an assignment, and you should give the user what the user asked
for.

I also find it odd that

{
let x = 0;
for (; x  n; x++) ...
}

should have different behavior than

for (let x = 0; x  n; x++) ...


-Jon
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Brendan Eich
On Oct 14, 2008, at 7:17 AM, David-Sarah Hopwood wrote:

 This is subject to the criticism that the loop variable(s) are
 implicitly mutable in the update expression (only), when they were
 declared it to be const.

My point was simpler: sometimes it is handy to write for (const x...)  
and have no fresh binding for x, even though the loop iterates. It's a  
corner case that falls out of parsing var x and const x using the same  
top-down procedure, so not rejecting const where var is allowed. It  
arguably simplifies both implementation and user modeling of the  
grammar.

We could certainly reject for (const ...; ...; ...) loops if we saw  
this as an anti-use-case.


 No such criticism would apply to 'for each (const ...', though.

Right -- this is pure win.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Brendan Eich
On Oct 14, 2008, at 7:17 AM, David-Sarah Hopwood wrote:

 Requirement 3 is met because var hoists to the enclosing function.

 Assuming that var hoisting is done before this expansion, yes.

Absolutely -- var hoisting across lambdas to preserve TCP is prior  
magic, assumed by the (revised) lambda proposal. In principle it could  
be lambda coded but I don' t believe the result would be particularly  
illuminating.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Waldemar Horwat
Jon Zeppieri wrote:
 On Mon, Oct 13, 2008 at 10:48 PM, Mark S. Miller [EMAIL PROTECTED] wrote:
 You're right. However, the desugaring is more complex than I expected.
 Thanks for asking me to write it down.

  for (keyword varName = initExpr; testExpr; updateExpr) { body }

 desugars to (hygienic  renaming aside):

 breakTarget: {
  const loop = lambda(iter = initExpr) {
keyword varName = iter;
if (! testExpr) { break breakTarget; }
continueTarget: { body }
lambda(iter2 = varName) {
  keyword varName = iter2;
  updateExpr;
  loop(varName);
}();
  };
  loop();
 }

 I believe this meets all your requirements.
 
 I believe it does.  Very cool.  It won't handle the fully general
 for(;;).  E.g.,
 
 for (let fn = lambda(n) { ... fn(...) ... }; testExpr; updateExpr) ...

Yeah, that's a problem with the current formulation.

 I also find it odd that
 
 {
 let x = 0;
 for (; x  n; x++) ...
 }
 
 should have different behavior than
 
 for (let x = 0; x  n; x++) ...

I do too.

Another issue with the rewrite is that it interacts badly with getters and 
setters on the iteration variable.

Waldemar

PS.  What does lambda(x = y){...}() mean?  Is it different from 
lambda(x){...}(y)?  What does lambda(x = y){...}(z) do when z is undefined?

___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Brendan Eich
On Oct 14, 2008, at 12:39 PM, Waldemar Horwat wrote:

 PS.  What does lambda(x = y){...}() mean?  Is it different from  
 lambda(x){...}(y)?

No.

  What does lambda(x = y){...}(z) do when z is undefined?

Passes undefined bound to x. Undefined is not the same as missing.

These are my answers based on past default parameter proposals from  
ES4 which met with approval at the Oslo meeting. Others will no doubt  
shout if they seem wrong.

/be

___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-14 Thread Brendan Eich

On Oct 14, 2008, at 1:36 PM, Brendan Eich wrote:


On Oct 14, 2008, at 12:39 PM, Waldemar Horwat wrote:

What does lambda(x = y){...}(z) do when z is undefined?


Passes undefined bound to x. Undefined is not the same as missing.


Lest anyone think otherwise, missing means actual argument count is  
less than number of formal parameters. It's not yet another undefined- 
like value code.


The implementation knows that lambda has arity 1 with a default  
parameter value. It knows the call passes an actual (that its value is  
undefined does not matter). So the default parameter value is not used.


Default parameters are evaluated once when the lambda expression is  
evaluated. That the lambda is immediately applied in your questions'  
examples may make this point unclear. This is why my answer to your  
question:



lambda(x = y){...}() mean?  Is it different from
lambda(x){...}(y)



was No. But if you captured the lambda and applied it elsewhere to a  
different y (y in a different scope chain), this equivalence would not  
hold. Hope this is all non-controversial (modulo blunders on my part  
explaining it).


/be___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: For Loop Desugaring (was: return when desugaring to closures)

2008-10-13 Thread Brendan Eich
On Oct 13, 2008, at 7:48 PM, Mark S. Miller wrote:

 On Mon, Oct 13, 2008 at 5:00 PM, Jon Zeppieri [EMAIL PROTECTED] wrote:
 1) for (var i = 0; i  len; i++) ... continues to mean what it  
 means in ES3.
 2) for (let i = 0; i  len; i++) ... has the proper scope for 'i'
 (which you reiterated above), *and* 'i' is rebound -- not mutated --
 on each iteration.
 3) The rewrite rules are the *same,* regardless of whether it's a  
 for
 (var ...) or a for (let ...) loop.

 At least, that's what I took Mark to mean.  He can correct me if  
 I'm wrong.


 You're right. However, the desugaring is more complex than I expected.
 Thanks for asking me to write it down.

  for (keyword varName = initExpr; testExpr; updateExpr)  
 { body }

 desugars to (hygienic  renaming aside):

 breakTarget: {
  const loop = lambda(iter = initExpr) {
keyword varName = iter;
if (! testExpr) { break breakTarget; }
continueTarget: { body }
lambda(iter2 = varName) {
  keyword varName = iter2;
  updateExpr;
  loop(varName);
}();
  };
  loop();
 }

 I believe this meets all your requirements.

Requirement 3 is met because var hoists to the enclosing function.  
This is the part I missed -- well done.

Note that continue; in body translates to break continueTarget; and  
break; translates to break breakTarget; -- you knew that ;-).

 However, in contradiction
 to my original claim, one couldn't usefully say const instead of
 let with a for(;;) loop.

Why not usefully? It's true the consts do not hoist to leave an effect  
in the variable object, but they do ensure const-ness. The body and  
update cannot mutate the nearest varName binding. This is sometimes  
useful and existing const implementations allow for (const...). I do  
not think it should be rejected just yet.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss