Re: For Loop Desugaring (was: return when desugaring to closures)
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)
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)
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)
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)
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)
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)
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