Tennent's correspondence principle and loop-local variable capture

Brendan Eich brendan at mozilla.com
Thu Jun 30 16:07:29 PDT 2011


On Jun 30, 2011, at 3:33 PM, Vladimir Sedach wrote:

> Hello,
> 
> I was recently pointed to the block scoping and TCP discussions by
> Peter Michaux, and have a question as to how this will affect the
> capture of loop-local variables by closures created in loops.

A well-known sore point.

The good news is that for-in and for-of loops in ES.next, when using let (or if implicitly using let, in comprehensions, generator expressions, and possibly even the for-of loop statmeent) not var, will result in a fresh binding per iteration:

http://wiki.ecmascript.org/doku.php?id=harmony:iterators


> Some programming languages (Common Lisp in particular) assign a new
> binding to loop-local variables on every iteration. JS doesn't do
> this, but there is a way to introduce a new lexical environment on
> every iteration with the WITH statement, an idea that I first
> encountered in the Scheme2JS compiler
> (http://www-sop.inria.fr/indes/scheme2js/). Parenscript uses this
> trick for translating Common Lisp to JS (a good discussion of how this
> shows up in loops is here:
> http://lists.common-lisp.net/pipermail/parenscript-devel/2010-December/000914.html).
> 
> However the WITH statement is deprecated. How can per-iteration
> loop-local variable capture be accomplished with the current proposal,
> and what effect does the Block Lambda Revival proposal have on this
> issue?

See above. 'with' is not lexical in any sense, and it has been removed from ES5 strict mode, so it is gone from Harmony / ES.next.

'let', on the other hand, is the new var, and we have the opportunity to make a fresh binding per iteration when for-in/-of is used with 'let'. This is the way to go.

The old C-style for(;;) loop is a hard case. It really does want a single shared-mutable loop control variable. Making 'let' instead of var in for (let i = 0; i < N; i++) ... bind afresh on each iteration and communicate the ++ update across the loop edge is theoretically doable, but it's wrong. There's really only one binding there.

So for-in/-of will benefit with 'let'. Is that enough? If not, you can always nest an explicit block inside the loop and capture its 'let' bindings.

/be



More information about the es-discuss mailing list