lexical for-in/for-of loose end

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Feb 6 11:08:43 PST 2012


On Feb 6, 2012, at 7:59 AM, Brendan Eich wrote:

> Andreas Rossberg wrote:
>> ...
> 
> Yes, this is something Jon Zeppieri brought up as a reason not to do fresh-binding-per-iteration in for(let;;) -- moving the initializer part out of the loop loses the binding-per-iteration.
> 
> You've shown b-p-i restored manually, with i_ vs. i renaming, but in the likely scenarios the user sees only one "i" variable.
> 
> Try this version:
> 
>  let i = 0, skip2_ = function(){i++};
>  for (; i<  N; i++) {
>    foo();
>    if (bar())
>      skip2();
>  }
> 
> This must "work" (skip2 must advance the one i binding; note no closure capture here) just as it does today. Jon was arguing against a change in binding semantics simply due to moving the let into the for-head.
> 
> We who were in the TC39 meeting room late the second day have overcome Jon's good counter-argument. For the greater good on balance, many of us TC39ers want to make for(let;;) a special form, so closure capture works as most users expect.
> 
> You're right that the trade-off where skip2 fails to update any useful loop variable (or the first iteration's loop variable only -- agreed that is odd) follows from this greater-good choice. But could we do better?
> 
> Making dynamic errors out of skip2-like capture seems bad. We can't guarantee early errors. Probably best to avoid adding error cases...

I probably could be made an early error.  Whether or not that would be a good things is a different issue.

> 
>> Probably not what the programmer expected, but as others have said,
>> it's a trade-off. This use case seems rare,
> 
> Agreed on "rare".
> 
>>  rather obfuscated style
> 
> This isn't so clear to me, since the case where the let is manually hoisteid from the for head does "work", and hackers who learned C or C++ may think that moving the let into the head is just better style, not obfuscatory.

Also, while it doesn't make a lot of sense for i++ it might if the actual "skip" code code was a complex expression containing long names or if it occurs at multiple places in the loop body.

> 
>> IMHO, and you can easily work around it. So probably not something you
>> want to be optimizing the language semantics for.
> 
> I agree with you, but feel a small nagging doubt.

We're putting a lot of energy into trying to figure out how to "fix" for(let;;) when it probably shouldn't even be the preferred form of numeric looping going forward. If we can make for-in/for-of attractive enough then it is less clear why we need to fix for(;;)

for (var i=0, n<n; I++) capture(function () {i});

still have to be modified to 

for (let i=0, n<n; I++) capture(function () {i});

to "fix" the capture bug in existing code. Why not make the new better way something like

for (let i of range(0,n)) capture(function () {i});

and promote the hell out of it while leavingfor(;;) as is.  Maybe don't even add let/const forms to for(;;).

Allen


More information about the es-discuss mailing list