return when desugaring to closures

Brendan Eich brendan at
Mon Oct 13 16:39:31 PDT 2008

On Oct 13, 2008, at 4:14 PM, Jon Zeppieri wrote:

> Yes, and binding a fresh induction variable on every iteration makes
> sense for a 'for-each' loop (as in the bug report you cited), where
> the user is not in charge of updating the induction variable by means
> of explicit assignment.  In a plain 'for' loop, however, it *is* magic
> if an assignment results in a fresh binding.

Why is the assignment operator relevant? The question is the binding  
scope of i in

   for (let i = 0; i < N; i++) ...

No curly braces required, we already have this in JS1.7+ and the let  
is scoped to the for head except for the initializer of i (you can  
write let i = x, j = y; too -- x and y are evaluated in the outer  
scope). There's scope magic in this form even though it uses = for  
assignment and creates only one block scope for the loop, no how many  
times the loop iterates.

>  And it's unexpected magic.

Users differ on this point, but we've had long-standing confusion and  
complaints about closures capturing the last value of i in

   let a = [1,2,3,4];
   let b = [];
   for (let i = 0; i < a.length; i++)
     b[i] = function () { return i*i; }

and the like. Getting 16 back from b[0]() is unexpected bad magic.

Users may be modeling closures as capturing bindings, not scope chains  
of mutable objects, one per for (let...) statement or explicitly  
braced block. If so, could we make let declaration capture this way?  
Again, I'm proceeding from real users' complaints, not idle wishes.

> Mark said that there was a desugaring for 'for' to 'lambda,' without
> special cases, where this all works out, but I haven't been able to
> figure out what rewrite he had in mind.

Tail-recursive lambda rewrite of a C-style for loop should be easy for  
you :-P.

>> Doing it the way Mark proposes fixes the bug, and has no other bad
>> effects that I can see (but we'll have to implement and user-test to
>> be sure).
> Turning an assignment into a non-assignment is bad.

Assignment is not the issue, the binding's scope is.

> Like I said, it makes sense for 'for-each.'



More information about the Es-discuss mailing list