return when desugaring to closures

Brendan Eich brendan at
Tue Oct 14 09:27:52 PDT 2008

On Oct 14, 2008, at 7:38 AM, Neil Mix wrote:

> On Oct 13, 2008, at 6:39 PM, Brendan Eich wrote:
>> 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.
> Are you suggesting that closures over let capture bindings in the
> general case?  I hope not.  I think for loops are a special case,
> otherwise let is not the new var.  ;)

What about for-in loops?

I'm proceeding from user expectations being confounded. Something  
needs help here, possibly not for (;;) loops -- but almost certainly  
for-in loops containing closures capturing the loop variable.

> WRT for loops, it's important to remember that let provides an
> alternative that wasn't possible with var.  Suppose for moment we do
> *not* rebind on every iteration:
>   for (let i = 0; i < objects.length; i++) {
>     let j = i;
>     objects[i].callback = function() {
>       print(j);
>     }
>   }

Yes, this is in the bug I cited ( 
). It is still a PITA.

> The syntactic overhead for such a workaround is much less than for  
> var:
>   for (var i = 0; i < objects.length; i++) {
>     objects[i].callback = buildCallback(i);
>   }
>   function buildCallback(i) {
>     print(i);
>   }

True, which makes it even more painful in some ways. "Why doesn't JS  
do it for me?" Closer, almost-but-not-quite-right, is torturous.

> The for/closures "bug" is definitely a newbie trap, but its pain is
> not its discovery, but the difficulty of working around it.  To me
> this could be a winning argument against re-binding on each loop,
> since re-binding precludes the (admittedly dubious) use-case of
> updating inside the body:
> for (let i = 0; i < 100; i++) {
>   if (skipAhead) {
>     i += 9;
>     continue;
>   }
>   ...
> }

So we can have our cake and eat it too with a tail-recursive  
desugaring that forwards the previous iteration's binding value to the  
next iteration's binding. Of course any practical implementation will  
have to do more analysis than is currently done in the top open-source  
implementations I've looked at. Could be worth the cost (VM hackers  
can take the cost for the larger team of users). What do you think?


More information about the Es-discuss mailing list