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