On Feb 3, 2012, at 6:42 AM, Jason Orendorff wrote:

> On Thu, Feb 2, 2012 at 8:08 PM, Allen Wirfs-Brock <al...@wirfs-brock.com> 
> wrote:
>> On Feb 2, 2012, at 5:07 PM, Jason Orendorff wrote:
>>> On Thu, Feb 2, 2012 at 5:52 PM, Allen Wirfs-Brock <al...@wirfs-brock.com>
>>> wrote:
>>>> for (let i=(geti = function() {return i},expr), expr, incr = function(i++),
>>>> decr=function(i--), cmp=function(){return i<n}; cmp();incr()) {
>>> 
>>> What?! We should not reward people writing code like that.
>> 
>> No reward, it is simply what the current syntax permits, and it is important
>> that semantics are consistently applied.
> 
> Oh, I definitely think we should have consistent semantics. It's
> difficult, because for(;;) is complicated, but it's worth the effort.
> Consider:
> 
>    for (let V in EXPR) STMT
>    for (let V of EXPR) STMT
>    for (let V = EXPR; ...; ...) STMT
> 
> I propose that in all three cases, the code that runs once, before the
> first iteration, namely EXPR, should be evaluated outside the scope of
> the loop variable. STMT should be evaluated within the scope of a
> per-iteration binding for V. The same semantics in all three cases.
> That seems to me both consistent and sensible.

the above is how I currently have it spec'ed for the first two cases.

the third case is different in several ways. Including:
   let V =EXPR is a distinct syntactic pattern that has a specific semantics  
that requires that the EXPR is evaluated in the same scope as EXPR. However, in 
most cases (but consider |et x=(x=5,++x);) all of EXPR will be in V's temporal 
dead zone. 
   The actual syntax is for (let V1=EXPR1, V2=EXPR2,...;...) STMT Again, the 
semantics for such declarations is that all of the Vs are defined in the same 
scope and EXPRn+1 is outside the TDZ for for Vn.

Using your semantics for the 3rd form would mean that its let clause was not 
consistent with let declarations in all other contexts. 


> 
> What is even more important than consistency is that the language work
> for people. We know that *not* having per-iteration bindings
> astonishes users, because that's how SpiderMonkey does it, and people
> are regularly astonished.
> 

I think you are over generalizing from a specific use case.  This bug cuts both 
ways.

Programmers would always love to have a "do what I mean" language. When they 
are in the zone they often write code that reflects what they want to happen 
rather than what their language actually does. It's true that when programmers 
want a per-iteration binding they are astonished when they don't get one. 
However, it is also true, that when a programmer does not want a per-iteration 
binding they are astonished when they get one.  Both situations occur in 
practice, A programmer's intuition of the "right thing" may just be a 
reflection of which of these bugs most recently bit them.

For the sort of loops written using  for-in and for-of (with let/const 
bindings) I think we agree that there is a high probability that programmers 
will want a per iteration binding. 

However, it is a lot less clear that this is the case for the  for(;;) form.  
This statement is one of the most idiosyncratic  syntactic forms of the the C 
syntax family of languages. Idioms for using it a generalized loop  construct 
(not just a simple counting loop) are well known.  Sometimes  parts of the loop 
logic that could be placed in a header expression are written in the loop body 
and sometimes code that could go into the body is placed in one of the header 
expressions.  Programmers who have experience with various C family languages 
have an expectation for how such for(;;) statements  work. Given this legacy 
and the variety of usage patterns it is a lot harder to generalize about  
whether programmers will  usually want per loop or per iteration bindings.  


>> Plus, the desugarings aren't things that are really suitable for teaching
>> the semantics to everyday JS programmers.  You instead have to say something
>> like:
>> 
>> Ok, this is really complicated but here goes.  For each let/const declared
>> in the for header, a fresh variable is located in the loop body for each
>> iteration of the loop. However, the values of the loop variables are
>> automatically copied from the previous iteration into the next iterations.
>>  This means that basic expression operator will work in the loop header
>> pretty much like you would expect.  But be careful if you use any function
>> expressions in the for header because the loop variables they reference may
>> not be from the current iteration and any changes to loop variable they make
>> may not have the effect you intended.  But, hey you probably shouldn't do
>> those things so it really doesn't matter what it really does.
> 
> This "explanation" seems oriented more towards making a rhetorical
> point than explaining. If I had to explain this to an everyday Web
> programmer, I would just write the three lines of code above and point
> out the consistent behavior. That way is simple, and it explains
> several things at once.

Yes, but you really wouldn't be explaining the behavior of the loop head 
expression.  It may be enough to get people started writing simply cases like 
the the one you show below but it really isn't teaching the actual semantics 
and its possible gotchas.
> 
> Anyway, this kind of argument certainly isn't going to win me over,
> because the reason I want this change in the first place is so I can
> do less explaining! People do write code like this:
> 
>    for (let i = 0; i < n; i++) {
>        buttons[i] = makeButton();
>        buttons[i].click(function () { alert("pushed button " + i); });
>    }
> 
> It fails to work because in SpiderMonkey the binding isn't
> per-iteration. Then I have to explain. Per-iteration bindings mean
> less explaining, because fewer people will hit problems. Their code
> will just work.

But it works just like most other C family languages. Either way people 
sometimes will gets something that they didn't mean

Woundn't it be better to be able to teach people to write:

   for (let i of  range(0,n-1)) {
       buttons[i] = makeButton();
       buttons[i].click(function () { alert("pushed button " + i); });
   }

People who are beginning programmers or who don't have a background with C 
syntax find the whole for (;;) thing intimidating anyway.  Rather than trying 
to fix for(;;) to DWIM, why don't we just offer a better alternative and 
deemphasize use of for (;;)

Allen



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

Reply via email to