Jumping in late, and possibly repeating some already covered ground, but this
is clearly an important topic.
Looking at all the proposals on these threads, I have to throw support behind
Mark's proposal below, or a close variant of it as discussed below and in some
of the other branches (I think this is close to what Brendan has been
advocating as well?). Let me try to motivate this from a somewhat different
direction. Wall of text below - but the punchline is:
Let's avoid versioning by making (almost) no breaking changes.
# Versioning #
There are two goals to versioning - (1) allow breaking changes that code can
explicitly opt-in to and (2) support reasonable forward compatibility of new
code running on old runtimes.
The original plan for ES6 was to support (1) and (2) via a versioned script
tag. This allowed breaking changes because it was explicit opt in, and
supported forward compatibility to the extent that there was graceful
degradation of behaviour on old runtimes (skipping the script block).
Versioned script tags are onerous though, and folks are rightly looking for
better options.
The better option is to not do versioning at all. To do that, you need to give
up on (1) and (2). That is - no breaking changes (or at least no practically
significant ones), and no 1st class support for forward compatibility.
# Forward compatibility #
The forward compatibility point in favor of a versioned script tag was never
particularly strong anyway. A versioned script tag is ignored on most down-rev
browsers, but it is still hard to construct programs using new syntax that
behave pleasantly on those browsers, because the granularity of feature
detection is at the script-block level, not the application-feature level. To
the extent that apps want to use new syntax and still work on older browsers,
they can almost as easily just accept the early errors from their <script>
blocks and detect whether they got past early errors successfully in a later
block in the same way they would with a versioned script tag. So giving up the
forward compatibility support doesn't appear to sacrifice much.
# Breaking changes #
Breaking changes are different. There are quite a lot of breaking changes in
the current ES6 proposals. This is somewhat unsurprising, because for the
history of development of ES6 proposals to date, the assumption has been that
ES6 will be explicit opt-in for syntax. So we accepted all sorts of breaking
changes based on that barrier to entry, and developer expectations associated
with explicit opt-in. But now we want to not do versioning for ES6. So the
bar for breaking changes should necessarily be much, much higher.
As Mark noted below, this higher bar should effectively disqualify "typeof
null", completion reform (if the break is significant enough to matter in
practice), and removal of the global object from the scope chain. I believe
these are reasonable things to give up in favor of not having to version.
The next big breaking change is implicit strict mode in ES6. Because it was
designed with an explicit opt-in in mind, strict mode has lots of breaking
changes which we can never offer unversioned. As with the above, we should
give this up. The result is effectively what Mark describes - "use strict"
remains the opt-in to the strict mode breaking changes.
The last set of breaking changes are reserved words. As Mark notes, in strict
mode many of the new keywords are already reserved, and so strict mode can
allow "let" et al.
However, I think we can go further than that (as Brendan and Allen I think also
pointed out?). In Dave's original proposal, he showed how "module" can be
introduced as a contextual keyword. I believe we can do this for many more of
the features as well. And for those that can't, we should look for potential
alternative syntax that can be introduced as contextual keywords.
Classes were raised as a counter example here in a branch of the thread. But
it seems they can be handled nearly identically to "module" - as a contextual
keyword with appropriate restricted productions.
let[x]=[5] was also raised as well on one of these threads, as a reason why
"let" cannot be made contextual. This one does seem harder to get out of - but
given how corner case this break is, we could allow this to be resolved as a
let binding and accept the very minor breaking change in just this corner case,
treating "let" as a contextual keyword elsewhere.
So the extension to Mark's proposal is that most (possibly all) ES6 syntax is
also allowed without "use strict", but with the design modified wherever
necessary to be (almost) fully backward compatible.
# Why 'implicit explicit opt-in' doesn't seem reasonable #
The prevalent alternatives presented in this thread are variations of "implicit
explicit opt-in", where use of some new syntax causes some part of the code
inside or outside of it to start behaving differently (breaking changes). I
think in practice this will be very confusing. Take this:
var x = typeof null;
module {
var y = typeof null;
x == y // false!
}
This is a refactoring hazard, much harder to find by code inspection than "use
strict", and just plain confusing. Alternatives like having a "let" inside a
function body automatically opt the body into the sort of behaviour above feel
ever more magic, and very hard to reason about thoroughly.
Moreover, these breaking changes all come at conceptual cost for JavaScript
developers. While we may think we are making things better by "fixing" typeof,
we are actually just making the section on typeof in Doug's slide deck longer -
he needs to describe both behaviours, and when to expect each. We already see
this with strict mode - the answer to "what does this JavaScript code do?" now
often has to be answered by "well, if it's in strict mode... otherwise...",
instead of a direct simple (even if not desired) answer. It is even worse in
these "implicit explicit opt-in" models. In those cases, the answer becomes
"well, if it's inside a 'module', or in strict mode, or inside a function which
contains anywhere inside it a 'let', or...".
Breaking changes, especially if opted into through "implicit explicit opt-in"
add to the total complexity of the language. Moreover, if there aren't
breaking changes, there is no need for "opt-in" at all.
# Conclusion #
Let's avoid versioning by making (almost) no breaking changes.
Luke
From: [email protected] [mailto:[email protected]] On
Behalf Of Mark S. Miller
Sent: Tuesday, January 03, 2012 1:24 PM
To: Allen Wirfs-Brock
Cc: Brendan Eich; es-discuss Steen
Subject: Re: ES6 doesn't need opt-in
Just Two Modes
This is a long thread and I've been completely busy with other things so have
not had time to do more than skim. So please understand if the post below
misses some context. The following is a summary of some principles that Dave
and just agreed to in a verbal conversation, but he hasn't had the chance to
look at the following text before I send it, so it may not quite speak for our
agreement -- I've substantially elaborated it since the text that Dave and I
looked at together. Dave introduced this thread with the slogan "just one
JavaScript", so I'll introduce the following with the (much less catchy) slogan
"just two modes".
* ES5's strict vs non-strict distinction remains the only mode distinction. ES6
thus has only the same two modes.
* ES6 non-strict mode must be practically upwards compatible from ES5
non-strict mode.
* ES6 strict mode must be practically upwards compatible from ES5 strict mode.
* In ES6, one can opt-in to strict mode in at least the following two ways:
"use strict"; // exactly as in ES5
or
module <ident>? {
in statement context. In other words, exactly as ES5 may begin strict mode at a
function boundary to apply to everything recursively contained lexically within
the function, in ES6 in addition, strict mode may also begin at a module
boundary and apply to everything recursively within the module. Code
recursively contained within a module is always strict; there's no way to write
non-strict code within a module. But a module, like a function, may be embedded
within a non-strict context.
* Code that contains such a module construct may run on an ES5 system or may
cause an early SyntaxError, depending on whether this ES5 implementation has
been extended to recognize the module construct. An ES6 system must of course
recognize the module construct. Thus, modules, as well as most other features
of ES6, may be deployed incrementally, just as many features of ES5 were
deployed incrementally in the transition from ES3 to ES5.
* We give up typeof reform.
* We do completion reform only if we judge it to be practically upward
compatible, with a dispensation to ES5 implementations to implement it without
penalty of being non-conformant. (Dave and I both expect it will in fact be
practically upwards compatible.)
* As with completion reform, if there are other cleanups we can make to ES5
that is practically upwards compatible, e.g., whose only incompatibility is
with test262, we can consider these for ES6 and absolve ES5 systems that adopt
these cleanups.
* We obtain a clean top level scope only by using loaders, which is
increasingly how I've been thinking of SES anyway.
* The identifiers that are reserved in ES5 only in strict mode are:
implements, interface, let, package, private, protected, public, static,
yield
ES6 features that use these keywords are available only in strict mode. Because
ES5 reserved them, this is fully upwards compatible with ES5. For other ES6
features that do not depend on these keywords, whether or not they must also be
available in ES6 non-strict code we need to take on a case by case basis.
* In ES6, nested named function declaration must be accepted and have the
agreed ES6 semantics in strict code. As advised at
<http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls>,
all major browsers currently reject nested named function declaration in
strict code, so accepting them with the agreed semantics in ES6-strict is fully
upwards compatible.ES6 remains as silent as ES5 about whether nested named
function declarations can appear in non-strict code or what their semantics is
there.
--
Cheers,
--MarkM
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss