ES6 opt-in, reloaded

Brendan Eich brendan at mozilla.org
Mon Jan 16 10:35:01 PST 2012


> Andreas Rossberg <mailto:rossberg at google.com>
> January 16, 2012 8:09 AM
> Some of the recent discussion regarding ES6 opt-in has been rather...
> scary.

It's es-discuss, don't be scared. Just working through a 
thought-experiment, however misguided in someone's view, is low-cost and 
needs a forum for discussion. Occasionally we are all mistaken about an 
idea being misguided, and the experiment will prove worth the cost of 
discussion.

> I would like to step back a bit, and try to identify the goals
> that we actually want to achieve. I think these are:
>
> 1. Make ES6 opt-in as convenient as possible.

Yes. We need to talk about what actually has happened on the web with 
opt-in attributes and modifiers, though -- not just try to build a 
minimized logic system that we think is convenient (mostly because it is 
minimized).
>
> 2. Avoid reliance on external features like script tags or mime types.
> (Not all JS is on web pages anyway!)

Just to be clear, the RFC4329 version parameter was never proposed as 
sufficient. It or something equivalent in the script type attribute is 
necessary on the web to hide new script from old browsers.
>
> 3. Provide as many incentives for switching to ES6 as possible.

This is a job for ES6 itself, not just its opt-in system.
>
> 4. Minimize necessary changes in programming style.

Taken one way, this excludes new semantics, since people have to build 
everything today using objects and closures. Making a virtue of 
necessity could kill almost any proposal (destructuring, generators, 
modules -- even let).

It's not clear how listing several variables to minimize helps if we 
don't have a trade-off formula against opportunity costs and cost of 
building everything more or less in today's style.
>
> 5. Minimize ES5-ES6 transitioning pitfalls.

Five fingers of fate. Only one used right now.
>
> 6. Avoid maintenance or refactoring pitfalls in ES6 itself. Avoid that
> ES6 programmers have to think about modes or feature sets at all.
> (This particularly should apply to non-savvy programmers!)

Amen -- this is the impetus for the "scary" discussion.
>
> 7. Minimize semantic complications (which tend to harm both
> implementations and programmers).

The Harmony page talks about doing this by desugaring where possible, 
extending kernel semantics only where necessary and with primitives that 
compose well.

This implies that a new, consolidated Harmony-era spec must define how 
extended semantics interact with strict semantics at least. But we may 
have assumed that we didn't need to define interactions with non-strict 
semantics. That raises the question of opt-in before us.

My point is that *if* opt-in usability demands defining extended vs. 
non-strict complications, then so be it. We should take the hit. Again 
minimizing all of 4 or 7 variables is impossible. There are trade-offs. 
Judging them well is an art and it does depend on usability in the large 
(your goals 1 and 6 may well trump 7).
>
> 8. Obviously, achieve full backwards compatibility.

We've considered marginally breaking changes, e.g. completion reform. We 
should discuss this one more if necessary.
>
> The various proposals in the thread were primarily aimed at (1), but
> AFAICS all fail on (6), to different extent. (There were mixed results
> for the other points.)

Agree that 1 vs. 6 is the fight to focus on here.

> Consequently, programmers would have to be
> aware which features put them into ES6 (and thus strict mode), and
> which are only available there, and that local changes could subtly
> change the meaning of unrelated program parts (due to strict mode), or
> even the whole program. Moving code could subtly change its internal
> meaning.

You made some good points already in the thread against this, phrased in 
terms of those strict-vs.non-strict semantic shifts (eval of var, 
arguments aliasing, a few others -- not terribly many). I'm happy to 
concede (I thought I did already) that was a mortal blow to "tainting" 
implicit opt-in where a Harmony feature at the last line of 60,000 would 
put the whole large program in strict mode.

Let's agree on this if we can (Allen may not).
>
> It's also worth noting that backporting

That is a loaded verb-form ("backporting"). Who says there is a separate 
older spec or implementation to which to port?

Yes, analyzing interactions requires reading the ES5 spec in non-strict 
mode. No, the result is not necessarily a port -- it's a patch (if you 
insist on hacking metaphors).

> new ES6 features to classic
> mode, as has been proposed by several people, clearly works against
> (3),

I object. 3 is misstated to assume "switching" means all-or-nothing. If 
ES6 has new features and they are worth using, developers will want to 
use them piecewise and conveniently. Assuming they will do so at the 
price of a leading "use version 6" or equivalent pragma is debatable. We 
shouldn't just assume this conclusion.

I think 3 should be stated as "Provide as many incentives for using ES6 
as possible". Here "using" does not demote making use of every last 
feature in every script. There's no need to require "switching" and it 
may be user-hostile to do so.

> and consequently, also against (5/6).

This does not follow. Users transitioning to use new features may be 
helped, not hindered, by we spec and implementation editors working 
harder. In particular allowing, e.g., destructuring in non-strict code 
may be boon to developers, whereas requiring them to maintain explicit 
opt-in pragmas before doing so simply to convenience spec editors and 
implementors may be a global loss.

The game theory is multi-party and the moral hazard for us as spec and 
implementation people is to optimize for our own convenience or assert 
that it's identical to developer usability. It's not.

> Similarly, opting in at
> smaller scope, as has also been discussed, is a blatant violation of
> (6) and (7), and works against (3), too.

Let's agree, based on your earlier arguments and also on Dave's point 
that lexical scope (free variable error analysis) won't work if opt-in 
is too local. This still does not mean that all extensions must be 
supported only under all-or-nothing early opt-in.
>
> So I have plea: let's keep it simple. Start from the simplest of all
> possible ideas and optimize from there. That is, opting into ES6
> through one simple declaration on the top of a program (and nowhere
> else). Otherwise it's ES5 unchanged.

You are arguing based on "simplest" without considering real-world 
usability. Too much a-priori system building makes a crashed sky castle, 
I've seen this over and over. On the web, a-posteriori wins.

On the web, people lose version opt-in pragmas and MIME type versions 
(Larry Masinter made this point about the latter but it applies to the 
former). On the web, we have "use strict"; in the middle of 
concatenations. We have Unicode BOMs in the middle. We have

<!-- hide script from old browsers

and

// -->

and even

-->

in the middle of .js files!

No plan survives contact with the enemy (Moltke) comes to mind.

Meanwhile, JS1 grew via ES1-5 and various implementations (SpiderMonkey 
and Rhino) without any such opt-in, *except* for two keywords we 
couldn't reserve (and some incompatible change attempts that failed, vs. 
goal 8 -- one example: I tried to make == and != strict in JS1.2 to get 
ES1 to switch, but that broke the web, wherefore === and !==).

> As far as I can see, that clearly
> wins, or is no worse than other proposals, on anything but (1).

I'm sure it wins for spec authors and implementors -- forking large 
parts of the spec might even "win" in the short term. These would all be 
bad for users, IMHO.
>
> Compared to Dave's original proposal, the only scenario on which it
> loses re (1) is if the program already consists of a module, in which
> case you'd still have to write the opt-in declaration. One can
> probably argue whether this is worth adding an extra rule (personally,
> I don't think so).

So I'd have to write

   use version 6;
   module {...}

instead of just

   module {...}

even though there's no backward compatibility issue? That's just mean! :-|

> If so, it would be enough to say that a module
> declaration as the _first_ statement in the program also opts in _all_
> of the program.

Why first if (as Dave's proposal in its minimal form did) a later module 
cannot affect earlier non-strict top level semantics? Again there is no 
backward compatibility issue. Why, as spec writer or implementor, do you 
care whether it's

<script>
     // non-strict top level code
</script>
<script>
     module {...}
</script>

or the concatenation?

<script>
     // non-strict top level code
     module {...}
</script>

Nothing in the spec or an optimizing implementation, if we assume module 
M is its own opt-in such that ... is in ES6, should care when processing 
the non-strict top level code.
>
> In either case:
>
> 1. You always opt in all of the program consistently.
> 2. It is obvious from the first line that you do.

First lines get lost or moved down all the time.

Making this an early error helps only assuming diligent testing in new 
implementations. That's not safe to assume.

> 3. This truly opts-in the toplevel (for whatever that means in detail).
> 4. A future ES programmer just needs to know one rule: start your
> program with _____.
>
> (I'm intentionally avoiding bike-shedding a concrete syntax for ____ 
> here.)

Yeah, it's ok -- but let's not keep cleaning the slate. We have RFC4329 
and browsers do hide new version= values. We have a proposal lurking 
about for "use version 6". Avoiding bikeshedding is one thing, avoiding 
usability testing and assuming the first-line selector wins is not 
justified.
>
> And before somebody brings it up: I do not fear that this will share
> the fate of strict mode, because there actually is plenty of incentive
> for using ES6 (especially, if we do _not_ extend classic mode).

Another assumption. There may be more carrots this time, but if the 
explicit opt-in requirement is too unusable in practice, then ES6 may 
bounce, or simply have slower adoption that we'd like, ceteris paribus 
(many variables here, hard to project -- let's avoid arguing based on 
our favored speculations).

My non-speculative argument rests on experience on the web. Version 
marks and other separators are mangled and lost all the time.

I believe we should offer well-defined <script type=...;version=...> 
opt-in for script content hiding from old UAs, and *in addition* 
belt-and-braces in-script-content version opt-in at a minimum, via some 
pragma such as |use version 6;|.

But I also believe these will be lost or simply not used, and adoption 
will be better if we define sensible (per your arguments against 
tainting from small to large extent) new-syntax-is-its-own-opt-in rules, 
per Dave's o.p.

The reason I believe this is our experience in past edition shifts and 
experimental extensions. Usability wins should tax spec-editors (if not 
implementors -- let's not assume the implementation costs of implicit 
opt-in are too high [*]) for the greater good of the JS developers.

/be

[*] SpiderMonkey has no runtime tests based on <script type="...; 
version=X"> values, if I'm not mistaken, and very few compile-time. And 
this is with quite a few extensions, including standard ones such as 
E4X. Yes, we learned some lessons at non-trivial cost, but these need 
not be re-learned from scratch by TC39.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120116/be0e3ea9/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: compose-unknown-contact.jpg
Type: image/jpeg
Size: 770 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120116/be0e3ea9/attachment-0001.jpg>


More information about the es-discuss mailing list