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