On Feb 4, 2012, at 9:49 AM, Brendan Eich wrote:

> I want off this merry-go-round! Let's recap:
> 
thanks for the recap...


> ...
> From the January 19th 2012 notes Waldemar took:
> 
> Discussion about scope of for-bindings.
> for (var x = ...;;) {...}  will, of course, retain ES1 semantics.
> for (let x = ...;;) {...}
> Allen: This will behave as in C++: x is bound once in a new scope immediately 
> surrounding just the for statement.
> DaveH: Strangely enough, this creates a new x binding in Dart at each 
> iteration.
> There's an alternative semantics that creates an iteration-local second x 
> inside the loop and copies it back and forth.  Debate about whether to go to 
> such complexity.  Many of us are on the fence.
> Waldemar: What happens in the forwarding semantics if you capture the x 
> inside a lambda in any of the three expressions in the head?
> If this happens in the initializer:
> DaveH's option: The lambda would capture an outer x.
> Alternative: The lambda captures a hidden second x.
> Waldemar's option: The lambda would capture the x from the first iteration.  
> The let variable x is bound once through each iteration, just before the 
> test, if
> ...

> --- end grant citation ---
> 
> 
> Ok, Brendan here. I agree we want to support multiple declarators for the let 
> or const in the for-head's initialization part.

check
> 
> I agree we want to capture the first-iteration bindings in any closures in 
> those declarators' initializers.

It isn't clear to me why capture first-iteration is abstractly any better than 
"capture a hidden second x".  In both cases, in most iterations of the loop, 
evaluation of any such captures is going to reference the "wrong" binding.  
From a user perspective, the main advantage I see for capture first iteration 
is that it has a slightly smaller window of wrongness.  The captures evaluated 
in the first iteration will reference the correction binding, while latter 
iterations reference the wrong binding.  From an implementation perspective, it 
is probably a bit simpler to not have the extra hidden binding for capture.

There is another alternative that I haven't seen mentioned.  Scope any closures 
in the initialization expression such that any references to loop declared 
binding resolve to undeclared bindings,

For example (using block lambdas for conciseness)
   for( let d1={|| d1}, d2={|| d1+d2};;)...

would actually be interpreted as if it was
   for (let d1={|| return {|| d1}; let d1,d2}(), let d2={|| return {|| d1+d2}; 
let d1,d2}();;)...

In words, any references to loop declarations capture uninitialized bindings 
that never get initialized.  If evaluated they will throw as accesses within 
the TDZ of the binding.

Always making such bindings (when used) a error seems preferable I(from a user 
perspective) than making the first iteration of a loop behave differently from 
subsequent iterations.

> ...

> Mutations to the first-iteration d1, ... dN bindings in any closures in 
> e1...N propagate to the second iteration.
> 
> Is this enough to restore the consensus we thought we had at the end of the 
> meeting day on January 19th?

I really don't like the first iteration is different semantics and think we 
should think about the above alternative.

However, such closure capture is very rare (could use of block lambda based 
patterns change that??) so it may come down to judgements about implementation 
costs.  Is capture first going to be significantly easier to implement than my 
alternative scoping? The answer is obvious to me.  In either case an 
implementation is like to special case loops with closure capture in their 
initializers.

Allen


_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to