On Nov 22, 2010, at 12:09 PM, Oliver Hunt wrote:

> On Nov 22, 2010, at 11:49 AM, Brendan Eich wrote:
> 
>> 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?
> 
> Proxies need to have a way to work with for(in) which is the only reason I 
> believe they should be allowed to have a trap for for(in) enumeration.  It's 
> necessary if you ever want to have DOM objects like NodeList be defined in 
> terms of proxies.

Yes, that's already in the harmony:proxies design via the enumerate trap.

You didn't answer my questions, though. If we were to add for (x : y) as you 
among others seemed to want last week, would it throw on a non-proxy on the 
right of :?

The answer matters both so we can hope to define for-: (whatever its syntax, if 
not for-in), and so we can reach agreement on premises. One premise: new users 
of Harmony implementations can just always use for-: as dherman said. They 
never have to use for-in. For enumeration, they use for (k in keys(o)). Agree 
or disagree? If you are indifferent then you're not really participating :-/.


>>>> - 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?
> 
> I'm not sure what relevance pure lexical scoping in harmony has to a 
> discussion on the behaviour of for(in).

It's a breaking change to the language's runtime semantics, but not to any 
syntax. It seems entirely analogous to the case of migrating for-in code from 
pre-Harmony into Harmony, and as I guessed last time, losing the global object 
looks strictly riskier in terms of unintended global property aliasing breakage.


> If we're saying that every new API and language feature being discussed for 
> harmony will only be available in harmony, then yes harmony can do whatever 
> it wants,

We are not saying that because we do not want gratuitous differences for users 
or implementors. This is pretty clear from all our work. If we really wanted a 
totally new language, not only would it make for roughly 2x the learning curve 
for users, and lots of confused-mode bugs, it would make implementors do a 
bunch more work, approaching 2x.

And as I also argued last week, TC39 would never pull it off. It would be 
design by committee and it would fail.

So (in case this isn't obvious; I thought it was), we are trying to extend ES5 
strict mode with only a few well-chosen runtime semantic shifts. Possibly "few" 
will be "one": the global object removal in favor of lexical scope.

New syntax brings new semantics of course.


> but you've also caused me to lose any interest in implementing harmony at 
> that point.

That's a straw man of your own devising, and I just knocked it down. Can we 
please get back to the crucial issues?


>  If every feature being discussed is only usable inside harmony code then the 
> migration cost of individual features won't be relevant as it's a distinct 
> language with no impact on ES.

There's still a migration tax in porting from old to new language, however 
similar they are. You yourself raised this re: ES5 strict, which changes 
runtime semantics without any syntactic change (eval-of-var, arguments). It is 
the same point I'm making about lexical scope removing the global object. I 
hope it is clear now, both as a risk and an opportunity!

But it was never an opportunity to make a totally new and different 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 don't understand why : was a mistake, the only counter argument i saw was 
> that it didn't work well with type annotations,

No, you just replied to Tom's arguments against for-: that did not depend on 
annotation syntax. That is another counter-argument, and you must have read it 
since you replied directly to his message.


> which i see no value in and aren't being discussed for harmony or es-next.  

Mark is putting guards up as a candidate proposal.


> Honestly I wish people would stop treating type annotations as something 
> important -- ES is a dynamically typed language, trying to shoe-horn static 
> typing in seems strange.

Guards, not types. Mark is right to want to avoid anything connoting static 
type.


>> 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.
> How do library authors help?  They can't add value enumeration of anything as 
> that will break any existing code that uses for(in) over any of their objects.

As Tom pointed out (re-read his message :-|), they can make enumeration work 
for large/lazy/infinite objects. No non-string non-keys required.


> And given the desire that the library writers have to make their libraries 
> paper over browser differences they're not going to introduce changes that 
> completely change object behaviour from one engine to the next.

That's a nice argument for not changing anything, but of course (as I keep 
saying ad nauseum here, since it is a perniciously selective argument), we are 
designing for the longer run. ES1 came after original JS; ES2 next; ES3 soon 
enough; long stretch of de-facto standards; then ES5. Progress happens, and we 
are planning on it and participating in it, not just giving up or trying to 
freeze things at some point.


> If there were a separate syntax, they could provide a custom iterator, and 
> tell devs it was there, so devs would be able to use the nicer enumeration 
> feature when they know that the syntax is available.

That's not what I meant by "near term", since the near term includes browsers 
that don't grok the new syntax. The use-cases of large/lazy/infinite proxies 
exist in all time frames, short and long run.


>>> 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?
> 
> I don't believe harmony-only is reasonable, it would mean that for a 
> developer to use just the new enumerator they would have to rewrite 
> everything to deal with the now missing global object.

That's not true in general. I can write for (k in keys(o)) ... in Harmony 
without rewriting everything to avoid keys being redefined if I'm using only 
code I control or know well.

So why is it an absolute -- why is it not "reasonable", ever, period full stop?

Migrating into Harmony, losing one's dependencies on the global object with 
early errors from the lexical scope checker built into the JS compiler, could 
be well worth the trouble.

Likewise, migrating to a meta-programmable for-in could be much better than 
having to rewrite to use new syntax, teach it to users, implement it, 
standardize it, wait for it to be deployed, etc.

These are trade-offs, not absolutes.

You write about what you "expect" and "believe", but that's no argument, it's 
an statement of your expectation or belief. It's circular unless you're arguing 
from authority.

We have to reason together, debate technical merits and demerits, argue about 
big picture and little, not lose the forest for the trees. Just saying "no" 
doesn't lead anywhere, and if you can say "yes" to lexical scope all the way 
up, then I think you're not being consistent.


>  And once again, i think using "harmony" as a mode switch to change behaviour 
> of things unrelated to lexical scoping is the wrong approach.


Can you please say why it's "wrong".

Why was lexical scope the only possible change?

I agree that lexical scope all the way up is important, and while I do not 
share Alex and Arv's optimism that TC39 can design and standardize much more in 
the way of new semantics for existing or new syntax (what I jokingly called 
superfunrubypythonjavascript), neither is it obvious that we can *only* remove 
the global object and thereafter freeze runtime semantics for all syntax that's 
in ES5.

>From that global object removal a bunch of new issues arise around the 
>standard library and modules. It's not a simple "just this one [big] change" 
>and anyway, we do not have agreement to stop all further evolution there.

Recap:

I proposed meta-programming for-in code that opts into Harmony, to address your 
specific concern about a proxy with an iterate trap on its handler leaking into 
pre-Harmony for-in code and being evaluated on the right of "in".

You responded by arguing that we don't want to change runtime semantics apart 
from removing the global object.

I reply that this is arbitrary and incomplete. We still have a world of 
trade-offs. We can only get so many right in committee and for the next edition.

Lexical scope is a big trade-off (semantics-breaking change); we seem to agree 
on that being worthwhile.

The committee already agreed that large/lazy/infinite objects are another, and 
that needs to be resolved for proxies, which are already in harmony:proposals 
status.

The solution offered for large/lazy objects (dropping infinite, lazy covers it 
better) is iterators. There's no counterproposal. The iterators proposal makes 
for-in metaprogarmmable, which leads directly to the concern about old for-in 
code being given a proxy.

I've addressed that with a quick "opt-in" solution. I really don't want to goto 
step 1 under Recap: and iloop. To avoid that, I think it's incumbent on you to 
give an argument, not just an assertion of belief.

I value your opinion, I'm sorry if I sound mean or pushy. If you don't want to 
make that argument, someone else who agrees with you may, or we'll just have to 
soldier on somehow. But since we came this far, I hope you can rally and 
respond to my query by saying *why* even opt-in-only for-in metaprogrammability 
is the "wrong approach".

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

Reply via email to