Closing over a loop variable is like closing over any other variable. The problem is with language-specific looping constructs and whether they translate into code that puts the loop variable inside or outside the loop.
For instance, if you use a while
loop in C#, Lua or JavaScript, the result in all three languages is the same (10). Ditto for a for(;;)
loop in JavaScript or C# (not available in Lua).
However, if you use a for (i in x)
loop in JavaScript, you'll find that each closure gets a new copy of i
(output: 0 1 2 3 ...
). Ditto for for i=x,y
in Lua and foreach
in C#. Again, that has to do with how those languages construct those loops and how they expose the value of the loop variable to the body of the loop, not a difference in closure semantics.
In fact, in the case of C#'s foreach
, this behavior changed from 4.5 to 5. This construct:
foreach (var x in l) { <loop body> }
Used to translate into (pseudocode):
E e = l.GetEnumerator()
V v
while (e.MoveNext()) {
v = e.Current
<loop body>
}
In C# 5, this was changed to:
E e = l.GetEnumerator()
while (e.MoveNext()) {
V v = e.Current
<loop body>
}
This was a breaking change, done to better meet programmer expectations when closing over the loop variable. The closure semantics didn't change; the position of the loop variable did.