On Nov 22, 2010, at 11:14 AM, Oliver Hunt wrote:

> On Nov 22, 2010, at 2:08 AM, Tom Van Cutsem wrote:
> 
>> My arguments in favor of keeping the existing "for-in" syntax and making it 
>> meta-programmable:
>> 
>> - Simplicity. Don't underestimate the complexity creep of introducing a new 
>> looping construct. Many small changes add up quickly. Especially for 
>> novices, having two looping constructs that are so similar will be terribly 
>> confusing.
> 
> You're not saving the addition of a looping construct, in making for-in 
> behave differently depending on what is on the right hand side of 'in' you're 
> merely adding an additional looping that is not syntactically observable.

Is the additional aspect important enough to split syntax over?

If so, would you make the new form *only* work on proxies and throw given a 
non-proxy on the right of "in"?

If not, why not?


>> - Keeping the existing syntax means that the tons of JS code already out 
>> there can instantly become client-code to iterators. As Brendan noted: you 
>> can use iterators to generate a stream of keys (strings) without confusing 
>> clients.
> 
> And all existing standards compliant code can no longer rely on for in doing 
> what it has done for years.  Suddently for in _behaviour_ may change based on 
> the prototype chain.

That's true in Harmony, and as you noted on the list a while ago, also true in 
ES5 strict. I decried too much migration tax but allowed we want to break 
compatibility for important wins. Lexical scope all the way up is one such 
proposed win, justifying removing the global object from the scope chain.

In my view, letting for-in be reformed by library authors is another case where 
the migration tax is worth it.

Now, I need to ask whether you are making an absolute statement: Harmony must 
be runtime as well as syntactically compatible with ES5 strict, i.e., a 
superset language?


>> - Client code to proxies that emulate objects with lots of properties can 
>> continue to use for-in. It just feels wrong that client code should change 
>> because of pure implementation details of an object (i.e. whether it eagerly 
>> or lazily generates its keys).
> 
> My understanding was that proxies would have a trap to allow them to generate 
> an array of strings to be used.

That's true, the fundamental trap is enumerate, but as noted on the wiki and 
pointed out by Waldemar when we reviewed proxies and moved them to 
harmony:proposals status, this does not work well for "large" and "infinite" 
objects.

We moved proxies to harmony:proposals status with the agreement that the 
iteration protocol would address such hard cases. The iterators proposal does 
that, including details about proxies as prototypes of other objects (you don't 
want to switch to iterate if you start with enumeration -- you must call the 
proxy handler's enumerate trap).

Last week we agreed toward the end of the meeting, with some lack of clarity 
about *how* to do this, to recast for (x in y) as for (x : keys(y)) and allow 
either enumerate or (if provided) iterate to be used to handle large/infinite 
objects.

Now the for-: syntax looks like a mistake, and we still haven't reworked things 
to address the required large/infinite cases.

I'm reviewing all this because I do not think everyone has kept up with the 
details. But the details matter, and they have some irreducible complexity we 
can't wish away. They motivate more than just the enumerate trap which eagerly 
returns all the property keys


>> Of course, if an object changes its behavior from iterating keys to 
>> iterating values, this breaks clients and they should be modified to use 
>> "for (var k in keys(obj))". But I don't see how this differs from any other 
>> such changes made to an object. The important thing to note here is that 
>> turning an object into an iterator requires explicit action by the 
>> programmer. If iterators were implemented ala Python using a magical 
>> "__iterate__" hook, then I'd complain because Harmony code could silently 
>> turn normal objects into iterators. But there's no such risk with this 
>> proposal.
>> 
>> I think that's a key point worth re-iterating: iterators and regular objects 
>> are sufficiently distinct so that there's no risk of automatically 
>> converting one into the other. There is only a risk to existing client-code 
>> if a Harmony programmer changes a normal object into an iterator. But at 
>> that point the programmer knows he's making a non-upwards-compatible change 
>> and clients should be changed accordingly. I don't see how the for-in case 
>> differs in this respect, fundamentally, from say, renaming a method.

> I do not expect the behaviour of for(in) to change from harmony to 
> non-harmony code.  Ignoring all other concerns it would mean the behaviour of 
> objects passed from a harmony context to a non-harmony context would be 
> unexpected.

That is a risk but it is not an absolute. It is one end of a trade-off. The 
other end is the benefit of avoiding new and hard-to-make-winning syntax, 
splitting for-in and for-: by dynamic type of what is on the right-hand side of 
in vs. :, complicating the surface language, and precluding library authors 
from helping in the near term.


> I'm kind of frustrated that after discussing all this last week, and 
> apparently getting to some kind of consensus, we've more or less instantly 
> gone back to what we had at the beginning of the meeting, where for(in) gets 
> magically overloaded and a developer has some magical way to understand what 
> a given for(in) loop is going to do.

"We" haven't gone back. The agreement at the meeting was fragile, a rushed 
compromise to overcome an objection that not everyone believes is an absolute 
that trumps the benefit in the trade-off. So we are revisiting. Recall too that 
Tom was not on the call for this part of the meeting, due to his time zone.

Frustration over this opening up again is not going to do much to alter the 
fundamentals. We need to keep arguing until we have shared premises and shared 
weights for costs and benefits. If possible.


>  If this was going to be the outcome why did we even spend time discussing 
> this?

Because we were trying to reach agreement. Who says failure is not an option? 
Failure is important. It also is not permanent. Making this into a one side 
must win and the other must lose game would be a mistake. The game is still on, 
and there can be more winners than losers.

I said at the meeting that we couldn't prove someone wouldn't mix Harmony and 
non-Harmony code and objects, and have non-Harmony code run for-in over a proxy 
with an iterate trap, and find some kind of surprise.

This is the down side. It is not so obviously terrible and fatal that we all 
agree to abandon meta-programmability of for-in. It's an unquantified risk, 
probably small -- greater than the ES5 strict migration tax risks (eval of var, 
arguments aliasing, caller/callee) and less than the Harmony lexical scope all 
the way up (no global object on scope chain) risks, in my best guess.

Suggestion: we make old for-in loops never run the proxy iterate trap. Only 
for-in code that opts into Harmony (analogous to "use strict" changing 
eval-of-var and arguments) gets the meta-programmability. What say you?

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

Reply via email to