Tennent's correspondence principle and loop-local variable capture
brendan at mozilla.com
Thu Jun 30 16:07:29 PDT 2011
On Jun 30, 2011, at 3:33 PM, Vladimir Sedach wrote:
> 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:
> 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:
> 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
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.
More information about the es-discuss