No more modes?

# Mark S. Miller (14 years ago)

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

Since we almost never get to retire anything that old code depends on, addition of modes (like "use strict") adds to implementation complexity. They understand why we needed to introduce the "use strict" mode switch specifically. But as we go forward, they'd really like to see ES-Harmony avoid further mode switches. If we keep ES-Harmony practically[1] upwards compatible from ES5/strict, then on a browser supporting ES-Harmony, "use strict" can be the way to opt in to harmony as well.

This has several implications.

  • New harmony keywords should already be reserved in ES5/strict. Or at least be so rare in actual code that their introduction does not create a practical conflict. (This restriction need not apply to contextually reserved words, provided that the context is one which would otherwise cause a syntax error.) AFAICT, all the already-accepted harmony proposals (< harmony:proposals>) obey this

restriction.

  • Likewise, new properties or global variables should be unlikely to conflict with those in existing code, though with feature testing this is a softer constraint. After all, ES5 (barely) survived the introduction of the new "JSON" global and (more easily) survived the introduction of the new reflective APIs. Accepted harmony proposals would add globals "Proxy" and "WeakMap" and the methods "Object.getPropertyDescriptor" and "Object.getPropertyNames". My guess is that all these are adequately non-conflicting.

  • ES5/strict implementations as deployed in non-beta releases should obey < conventions:recommendations_for_implementors>.

If they don't, then either a separate opt-in will be necessary or we will have to retreat from some of the accepted harmony proposals. For example, if browsers deploy a harmony-incompatible semantics for "let", "const", and nested named functions, and if ES5/strict code comes to depend on those non-standard extensions, then without an additional opt-in it becomes impossible to deploy harmony without breaking that code.

Going through the active strawmen, most are not particularly problematic on these grounds. Although < strawman:obj_initialiser_constructors>

is presented as if using a "constructor" keyword, if it goes forward I think we all expect it would actually use "class" instead. However, the module proposal currently uses "module" as a keyword, which is not reserved and is probably in active use. Could we use (the already reserved) "package" instead? And the module proposal would have harmony scripts as well as harmony modules be evaluated in a scope without the global object at the bottom of the scope chain. While I hate global scope and would welcome this cleanup, I don't see how to migrate script code to that discipline without an additional opt-in. (And indeed, the current modules proposals does rely on an additional opt-in to gate this change.)

Opinions?

[1] Making an ES5/strict error condition be a non-error in harmony is not formally upwards compatible, since old code could depend on that error. In the Caja design documents, we'd say that ES5/strict is a "fail stop subset" of ES-Harmony. Looked at from the other direction, such fail-stop supersetting is often practically upwards compatible, to be examined on a case by case basis, especially when the error in question is a syntax error.

# Brendan Eich (14 years ago)

On Oct 13, 2010, at 4:31 PM, Mark S. Miller wrote:

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

If this is an attempt to avoid <script type="harmony"> (harmony a placeholder for something more RFC4329-conformant), it's not going to work.

I dislike modes. Who doesn't? But this sounds like the "Versioning is an anti-pattern" shibboleth I've heard recently re: WebSockets. It does not reflect reality. At the limit, it's dishonest. The Web has grown with incompatible changes (e..g. ES1-5, CSS table layout, XHR), some of which were forced without a version change other than the usual user-agent revisions -- which forced content authors to do user-agent sniffing.

We need to face the music and do the right thing here: Harmony has new syntax, not simply new keywords. This means incompatible Harmony content must not be sent to downrev user agents. This, plus RFC4329, lead us to conclude that we should use a new <script type="..."> version parameter, if not a whole new type attribute value.

Since we almost never get to retire anything that old code depends on, addition of modes (like "use strict") adds to implementation complexity. They understand why we needed to introduce the "use strict" mode switch specifically. But as we go forward, they'd really like to see ES-Harmony avoid further mode switches. If we keep ES-Harmony practically[1] upwards compatible from ES5/strict, then on a browser supporting ES-Harmony, "use strict" can be the way to opt in to harmony as well.

This can't work if new syntax not specified by ES5 follows the "use strict".

This has several implications.

  • New harmony keywords should already be reserved in ES5/strict. Or at least be so rare in actual code that their introduction does not create a practical conflict. (This restriction need not apply to contextually reserved words, provided that the context is one which would otherwise cause a syntax error.) AFAICT, all the already-accepted harmony proposals (harmony:proposals) obey this restriction.

We don't know what Harmony is. Unless you have a time machine and there's only one universe, we can't future-proof yet.

Worse, new keywords are not so rare that they do not create practical conflicts. We at Mozilla did the leg work here. We took the effort to implement let and yield (let is in flux now in TC39, for the better but still the "better var", and anyway, this was 2006 when ES4 was going) in Firefox 2 / JS1.7. We found real sites using let and yield as unqualified names (parameter names, IIRC). Contextual keyword reservation did not help.

  • Likewise, new properties or global variables should be unlikely to conflict with those in existing code, though with feature testing this is a softer constraint. After all, ES5 (barely) survived the introduction of the new "JSON" global and (more easily) survived the introduction of the new reflective APIs. Accepted harmony proposals would add globals "Proxy" and "WeakMap" and the methods "Object.getPropertyDescriptor" and "Object.getPropertyNames". My guess is that all these are adequately non-conflicting.

Proxy is shipping in Firefox 4 betas. No problems reported.

Simple modules will help here, but we need to finish the spec and prototype and user-test. We can't future-proof yet.

  • ES5/strict implementations as deployed in non-beta releases should obey conventions:recommendations_for_implementors. If they don't, then either a separate opt-in will be necessary or we will have to retreat from some of the accepted harmony proposals. For example, if browsers deploy a harmony-incompatible semantics for "let", "const", and nested named functions, and if ES5/strict code comes to depend on those non-standard extensions, then without an additional opt-in it becomes impossible to deploy harmony without breaking that code.

The conventions aren't enough. See above.

The point about let, const, and function in block is good but I'll take it up in a separate message.

Going through the active strawmen, most are not particularly problematic on these grounds. Although strawman:obj_initialiser_constructors is presented as if using a "constructor" keyword, if it goes forward I think we all expect it would actually use "class" instead.

I don't see how reserving class (as everyone already is) helps. The new code will look like this:

<script> "use strict"; class SuperDuper {...} </script>

An ES5-or-below browser will read this and choke. What good does shipping this without a new <script type=...> type attribute value do?

However, the module proposal currently uses "module" as a keyword, which is not reserved and is probably in active use. Could we use (the already reserved) "package" instead?

There's no need for this. We should stick to module, since it can occur only in limited contexts (at the start of SourceElements).

But the whole premise that we can (a) guess the future; (b) avoid conflicts even as we add new syntax; is false.

[1] Making an ES5/strict error condition be a non-error in harmony is not formally upwards compatible, since old code could depend on that error. In the Caja design documents, we'd say that ES5/strict is a "fail stop subset" of ES-Harmony. Looked at from the other direction, such fail-stop supersetting is often practically upwards compatible, to be examined on a case by case basis, especially when the error in question is a syntax error.

A syntax error is not enough. It will not be detectable by old browsers so that they can fall back on ES3- or ES5-level content. It will cause a wasted script load, which blocks rendering in many browsers (especially old ones). It will present error reports on consoles, confusing users and wasting more cycles.

I don't think the "no more modes" plea is a coherent request or requirement. Can someone restate it in a credible, future-proof way?

Hixie and Maciej tried a few years ago, in effect (from memory, which may be wrong) trying to allow arbitrary syntax of the form

keyword ( expr ) { statements }

so that ES5 would have standardized syntax error recovery when keyword was unrecognized, and then future editions could add new keywords and content authors could at least hope that such statement constructs could be skipped by ES5-level downrev browsers.

This attempt foundered on ASI and regexp syntax. Waldemar remembers the details.

But anyway, this idea did not help let syntax, or yield as an operator (yield as a function is not problematic, but it stinks like eval). This simply was not future proof.

Worse, it provide no fallback mechanism for old browsers to select pre-Harmony content. A <script type="harmony"> tag doesn't either, by itself. Wherefore the MAX_ECMASCRIPT_VERSION idea from

proposals:versioning

mentioned in the current strawman:

strawman:versioning

This is the place to focus effort.

# Mark S. Miller (14 years ago)

On Wed, Oct 13, 2010 at 5:35 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 13, 2010, at 4:31 PM, Mark S. Miller wrote:

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

If this is an attempt to avoid <script type="harmony"> (harmony a placeholder for something more RFC4329-conformant), it's not going to work.

Declaring what the conclusions of discussions must be is not helpful. I am raising an issue. Let's discuss it.

Given <script type="harmony"> as an opt-in, I'm puzzled about how it would

work anyway. Since it is per script, not per frame, presumably

<script type="harmony">"use strict"; var e1 = eval;</script> <script>"use strict"; var e2 = eval;</script> <script ...>"use strict"; e1 === e2 /results in true/ </script>

In other words, that both harmony and non harmony code on the same page have the same binding for the global "eval" function. In that case, what does the following code do:

e2(' "use strict"; var module = 8;');

This is currently legal es5/strict code. As suggested by the modules strawman, it is not legal harmony code. es5/strict and harmony share a heap. I do not see a good answer.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 8:12 AM, Mark S. Miller wrote:

On Wed, Oct 13, 2010 at 5:35 PM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 13, 2010, at 4:31 PM, Mark S. Miller wrote:

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

If this is an attempt to avoid <script type="harmony"> (harmony a placeholder for something more RFC4329-conformant), it's not going to work.

Declaring what the conclusions of discussions must be is not helpful. I am raising an issue. Let's discuss it.

The shoe seems to be on the other foot, to be blunt. You knew about strawman:versioning and previous work -- did you raise the issue? It seems you met for two days with V8 folks and came back with "no more modes", ignoring the work we'd done in TC39 on exactly why opt-in versioning seems required, and how it might work. That is less than helpful.

Sorry for being grumpy, but wishing away modes or versioning won't cut it, here or for WebSockets or other new stuff. The Web has not always evolved backward-compatibly, nor can it always -- nor should it, since old forms die off and new forms are needed to prevent stagnation -- wherefore ES5 and its incompatible changes, just like ES3, ES2, and JS itself before them.

Wishing, assuming, or stipulating that the Web must stop changing incompatible under opt-in versioning therefore simply begs the question of why things are different this time. Assuming we can be modeless when we're adding new syntax contradicts 15 years of direct experience. It's true we had a "versionless" era since ES3 was finalized, sort of: you have to ignore all the

if (document.all { // IE code here, no getters/setters, no Array extras } else { // for the last four years or more, getters/setters, etc. }

versioning code.

Versioning happens. Object detection, a la document.all testing (or better, this.JSON testing in global code) is arguably best, although not without pitfalls.

The worst thing we could do is force developers to user-agent sniff. But that seems where "no more modes" is headed, because content authors cannot afford to send syntax errors with no fallback automation to downrev browsers.

Given <script type="harmony"> as an opt-in, I'm puzzled about how it would work anyway. Since it is per script, not per frame, presumably

<script type="harmony">"use strict"; var e1 = eval;</script> <script>"use strict"; var e2 = eval;</script> <script ...>"use strict"; e1 === e2 /results in true/ </script>

In other words, that both harmony and non harmony code on the same page have the same binding for the global "eval" function. In that case, what does the following code do:

e2(' "use strict"; var module = 8;');

This is currently legal es5/strict code. As suggested by the modules strawman, it is not legal harmony code. es5/strict and harmony share a heap. I do not see a good answer.

First, whatever the answer here, the overriding motivation for opt-in versioning remains. You can solve this a number of ways. The front-runner, which came out at the last TC39 meeting and was a surprise to me, is to make all Harmony scripts use lexical scope, not the global object. Doing so avoids this problem by making e1 not visible to non-Harmony scripts, because it is not a property of the global object.

Of course e2 would be a global property, so the question remains: if Harmony script can get at the global object, it can invoke e2 as an indirect eval. But the answer then to the question "what version is this indirect eval using to compile with?" must be pre-Harmony.

Indeed, we implemented this when we added 'let' and 'yield' keywords under opt-in versioning in JS1.7. ES5 strict reserves these under the "use strict" opt in. From ES5 10.1.1:

  • Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct call (see 15.1.2.1.1) to the eval function that is contained in strict mode code.

Thus there is already one bit of opt-in versioning state in ES5, which must be carried from direct eval's caller to callee. But indirect eval is non-strict without a "use strict"; in the eval'ed source string.

This strongly suggests doing the same for another bit of opt-in versioning, to the Harmony version.

Again, this is all a sideshow to the main issues I (re-)raised. It needs to be resolved but it does not remove the overriding reason for opt-in versioning: new syntax and semantics (lexical global scope), not merely new keywords. I'd like to hear those addressed.

# Boris Zbarsky (14 years ago)

On 10/14/10 11:12 AM, Mark S. Miller wrote:

<script type="harmony">"use strict"; var e1 = eval;</script> <script>"use strict"; var e2 = eval;</script> <script ...>"use strict"; e1 === e2 /results in true/ </script>

Is that last a given?

In other words, that both harmony and non harmony code on the same page have the same binding for the global "eval" function.

Is that a given?

# Mark S. Miller (14 years ago)

On Thu, Oct 14, 2010 at 8:29 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 14, 2010, at 8:12 AM, Mark S. Miller wrote:

On Wed, Oct 13, 2010 at 5:35 PM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 13, 2010, at 4:31 PM, Mark S. Miller wrote:

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

If this is an attempt to avoid <script type="harmony"> (harmony a placeholder for something more RFC4329-conformant), it's not going to work.

Declaring what the conclusions of discussions must be is not helpful. I am raising an issue. Let's discuss it.

The shoe seems to be on the other foot, to be blunt. You knew about strawman:versioning and previous work -- did you raise the issue? It seems you met for two days with V8 folks and came back with "no more modes", ignoring the work we'd done in TC39 on exactly why opt-in versioning seems required, and how it might work. That is less than helpful.

Sorry for being grumpy,

Apology will be accepted once you stop being so grumpy ;). I really am surprised by your tone here. I did not raise this issue before because I do not feel strongly about this issue. I also had never had a multi-day meeting with the V8 folks before. In the previous meetings and conversations we've had, they never communicated this objection to me. During that recent two day meeting, they did convey this objection, emphatically. This was new information for me. Now it is new information for you. Can we please calm down now?

# David Herman (14 years ago)

Given <script type="harmony"> as an opt-in, I'm puzzled about how it would work anyway. Since it is per script, not per frame, presumably

<script type="harmony">"use strict"; var e1 = eval;</script> <script>"use strict"; var e2 = eval;</script> <script ...>"use strict"; e1 === e2 /results in true/ </script>

That's not quite right, at least according to the simple modules design. But it's my fault for not spelling it out clearly enough in the strawman. In particular:

  • Harmony scripts would not have the legacy global object as a record in their scope chain
  • Harmony eval retains the same value and behavior as ES5-strict eval, i.e., it evaluates its code as legacy code, not as Harmony code.

Both of these are open to discussion, of course, but I offer them at least as counter-evidence to your implication that there's no answer to the versioning question other than eliminating modes.

The invariants of Harmony do not rely on not interacting with legacy code. You still get lexical scope, and ES5-strict eval is sufficient for that purpose. (When you run eval, of course, you're running code in a language that doesn't have full lexical scope.)

In other words, that both harmony and non harmony code on the same page have the same binding for the global "eval" function. In that case, what does the following code do:

e2(' "use strict"; var module = 8;');

This is currently legal es5/strict code. As suggested by the modules strawman, it is not legal harmony code.

It's perfectly legal. It's an indirect eval, regardless of whether it's being called from ES5-strict or Harmony.

es5/strict and harmony share a heap.

Yep, and that's fine.

I do not see a good answer.

As you say, that's why it's worth discussing.

# Mark S. Miller (14 years ago)

On Thu, Oct 14, 2010 at 8:57 AM, David Herman <dherman at mozilla.com> wrote:

Given <script type="harmony"> as an opt-in, I'm puzzled about how it would work anyway. Since it is per script, not per frame, presumably

<script type="harmony">"use strict"; var e1 = eval;</script> <script>"use strict"; var e2 = eval;</script> <script ...>"use strict"; e1 === e2 /results in true/ </script>

That's not quite right, at least according to the simple modules design. But it's my fault for not spelling it out clearly enough in the strawman. In particular:

  • Harmony scripts would not have the legacy global object as a record in their scope chain
  • Harmony eval retains the same value and behavior as ES5-strict eval, i.e., it evaluates its code as legacy code, not as Harmony code.

Both of these are open to discussion, of course, but I offer them at least as counter-evidence to your implication that there's no answer to the versioning question other than eliminating modes.

I can we why it seems that I was implying that, but I'm making more modular arguments than that. In any case, thanks for the clarification.

This issue by itself suggests that a harmony opt-in should be managed by a prologue / pragma at the beginning of a Program production[1], rather than an attribute on a script tag, so it can follow the same opt-in logic as "use strict" and apply to eval code as well. Thus,

e2(' "use harmony"; var module = 1');

could be illegal on browsers supporting harmony. And such evaled code would also not have the global object at the bottom of their scope chain. This in-language switch makes more sense to me than a markup-based switch such as <script ...>, and would allow the switch to be recognized in non-browser

environments such as commonjs.

I will address the more general "more modes" and compatibility direction questions for later messages.

[1] And possibly other productions like FunctionBody, as 'use strict'; does. For symmetry, I think perhaps it should. But the point above by itself only argues that it need be recognized at the beginning of a Program production. OTOH, recognizing it in a nested production likely raises scoping issues we'd like to avoid, which argues against the symmetric generalization.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 8:51 AM, Mark S. Miller wrote:

On Thu, Oct 14, 2010 at 8:29 AM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 14, 2010, at 8:12 AM, Mark S. Miller wrote:

On Wed, Oct 13, 2010 at 5:35 PM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 13, 2010, at 4:31 PM, Mark S. Miller wrote:

Recently, I met with the Google V8 team for two full days. One message that came through loud and clear, that I said I would relay to the list, is "please, no more modes."

If this is an attempt to avoid <script type="harmony"> (harmony a placeholder for something more RFC4329-conformant), it's not going to work.

Declaring what the conclusions of discussions must be is not helpful. I am raising an issue. Let's discuss it.

The shoe seems to be on the other foot, to be blunt. You knew about strawman:versioning and previous work -- did you raise the issue? It seems you met for two days with V8 folks and came back with "no more modes", ignoring the work we'd done in TC39 on exactly why opt-in versioning seems required, and how it might work. That is less than helpful.

Sorry for being grumpy,

Apology will be accepted once you stop being so grumpy ;).

I could try a different tack:

Forget all that went before in TC39, the world started with your meeting with the V8 team (who've done awesome technical work, although nothing for the evolution of the language -- but no matter!).

I'm intrigued by this "no more modes" idea! Tell me more. How do you avoid sending syntax errors to downrev browsers without fallback automation of some kind, in script or in the markup (or both)?

Does this help? It didn't really do much for me (see below for why).

I really am surprised by your tone here.

Try to see the other guy's point of view.

I see the desire for no more modes. As an implementor I share it.

However, the fallback or graceful degradation issue remains. If we have no new scrip ttype (RFC4329 version parameter on type="application/ecmascript", e.g.), then we have a problem.

Also, and this is not a minor point: Collin Jackson and I did some work on versioning in TC39, and we've discussed in many meetings and wik-page setting the problem of new syntax in Harmony vs. old browsers that do not parse it. This was an issue even in 2008, which IIRC was when (May TC39 meeting at Adobe San Francisco) the idea Hixie and Maciej advocated, of standardizing error correction for keyword-introduced statement forms analogous to if and while statements was discussed and found to be flawed (by Waldemar Horwat and Lars Hansen).

There's a fairly rich history here. We ignore it to our detriment, and at some loss of happiness on my part over starting the world afresh because the V8 team wishes for no more modes.

To be super-blunt, and this is nothing personal since you are doing great work on TC39, Google is a big company with many agendas.

On one hand we have V8 team folk, never participating in language evolution, indeed developing in stealth mode for two years and therefore implementing web-compatible junk like foo.arguments on function foo (my fault, the "junk" blame goes to me) instead of perhaps (or even while remaining stealthy) working to get this junk off of the public web, and now wanting "no more modes", which verges on "freeze the language", which is tantamount to stagnation.

On the other hand, we have many different groups at Google working to advance such things as sandboxed native code on the web!

Forgive me for objecting that such innovations constitute "modes" or versioning in a very big way. A version parameter on <script type="application/javascript"> is much simpler and easier to standardize and implement interoperably among the browser vendors!

So, again not picking on you, I'm a bit unapologetically skeptical, if not grumpy or hostile, to a "no more modes" pitch that ignores both the work we've done in TC39 and the larger context of web evolution, in which even Google is willing to make major version-like changes.

Most of all, I'm committed to the web not stagnating, but evolving sensibly and interoperably among various actively developed browsers. This still favors Harmony with opt-in versionin, in my view, over a "no more modes" attempt to predict the future or simply freeze ES5 as it is.

I did not raise this issue before because I do not feel strongly about this issue. I also had never had a multi-day meeting with the V8 folks before. In the previous meetings and conversations we've had, they never communicated this objection to me. During that recent two day meeting, they did convey this objection, emphatically. This was new information for me. Now it is new information for you. Can we please calm down now?

I will be as calm as a cloud. The objective issues: no syntax error, fallback of some sort that doesn't require user-agent sniffing, no freeze-the-future-at-ES5, remain. Now what?

[snip the rest of my message, which you cited without comment...]

Really, I am truly sorry if I am distracting from the substantive issues by objecting to the form and substance of your original post. But, I don't think the "politics" are immaterial, and we should probably sort them out. But to avoid more dancing around the substantive issues:

Would you or Erik please address the problem of avoiding syntax errors in old browsers, and allowing content authors to switch to fallback content without user-agent sniffing (ideally without another round trip, although that is state of the art today: document.write of a script tag, e.g. as done by Google analytics). These are the problems that "no more modes" does not begin to solve.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 9:21 AM, Mark S. Miller wrote:

I can we why it seems that I was implying that, but I'm making more modular arguments than that.

I appreciate modular arguments and expect no less from you :-). But however modular, the bigger issues I keep harping on remain. Still, this is a good separate topic so I'll add something.

This issue by itself suggests that a harmony opt-in should be managed by a prologue / pragma at the beginning of a Program production[1], rather than an attribute on a script tag, so it can follow the same opt-in logic as "use strict" and apply to eval code as well.

Maybe, but ES5 direct eval from strict code uses strict mode in the eval'ed program. No directive or pragma in that eval'ed program's source string (passed as the direct eval's argument) is needed.

So the directive may be a good idea (more below), but it is not necessary by the design of ES5 strict mode and direct eval. The same seems to apply to Harmony opt-in.

Thus,

e2(' "use harmony"; var module = 1');

could be illegal on browsers supporting harmony. And such evaled code would also not have the global object at the bottom of their scope chain. This in-language switch makes more sense to me than a markup-based switch such as <script ...>, and would allow the switch to be recognized in non-browser environments such as commonjs.

The problem remains syntax errors in top-level script. Developers are generally not going to write Harmony script if the only way to load it is via XHR, or else to encode it with escapes and so on in string literals fed to eval.

It's not an "either/or", though: script versioning a la RFC4329 and a "use harmony" pragma could both be worth having.

But if you only have "use harmony", then you cannot use it in script tags without inevitable syntax errors in old browsers on the new syntax that follows the pragma. This means you have to eval, and this is both onerous for developers and expensive (and different from script-loading) at runtime.

I will address the more general "more modes" and compatibility direction questions for later messages.

Please, let's get to this. Otherwise more-modular arguments about "use harmony" (which is still a mode, I note!) do not help resolve the crucial issues: fallback content selection for old browsers.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 10:14 AM, Brendan Eich wrote:

I will address the more general "more modes" and compatibility direction questions for later messages.

Please, let's get to this. Otherwise more-modular arguments about "use harmony" (which is still a mode, I note!)

One more observation on the modular argument:

"use strict"; as a string ignored by downrev browsers would be unproblematic if strict mode only introduced errors, not runtime semantic changes. But ES5 strict mode also changes the semantics of eval and arguments objects.

This requires double testing: old and new (ES5-conformant) browsers running the "use strict"; code, with best test coverage. Otherwise you could test only in the new browser and instead of simply finding "lint-like" problems made errors in ES5 strict mode, you'd get different behavior from what the same code gets in old browsers.

Adding "use harmony" adds "one more mode", but with Harmony changing semantics as well as adding syntax, this raises the testing burden. Now you might have 4 combinations to test, although since we base Harmony on ES5 strict, it's more like three: old pre-ES5 browsers, ES5 browsers, Harmony browsers.

I'm not arguing that this is good or bad. ES5 strict is a done deal; the spec is going to ISO now. And my opinion is that an opt-in Harmony mode or version selection mechanism of some kind is necessary.

I am arguing that we have at least "one more mode", and we need to engineer it either to fail hard on new browsers and work compatibly on old, or else be version-selelcted out by old browsers using some kind of fallback mechanism, even if scripted -- even if

<script> if (this.MAX_ECMASCRIPT_VERSION < 6) document.write("<script src='downrev.js'></script>"); else document.write("<script src='uprev.js' type='application/ecmascript;version=6'>"); </script>

This is not the best we can do but it is better than user-agent sniffing. And user-agent sniffing is what you'll get if you don't provide some better way.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 10:28 AM, Brendan Eich wrote:

<script> if (this.MAX_ECMASCRIPT_VERSION < 6) document.write("<script src='downrev.js'></script>"); else document.write("<script src='uprev.js' type='application/ecmascript;version=6'>"); </script>

This is not the best we can do but it is better than user-agent sniffing. And user-agent sniffing is what you'll get if you don't provide some better way.

The problem could be addressed with markup extensions. Today, even in browsers that violate RFC4329 by ignoring ;version= parameters on <script type="..."> type attribute values, the following code "works":

<script src="always.js"></script> <script src="new.js" type="application/ecmascript-harmony"></script>

But you have to use a novel script type, not standardized by RFC4329 or anything else, for "new.js". And you always load "always.js".

Note how with HTML5's video tag, after <object> and <embed> and other precedents, you can nest fallback content inside the container tag. Alas, the script tag's content model (CDATA) precludes this.

But what if one could write this instead?

<altscript src="new.js" type="application/ecmascript;version=6"> <script ...> </script> </altscript>

Then we could have no round trips and fallback in the <altscript> container. This would entail no syntax errors, no extra round trips (beyond what current best practices motivate), and no freeze-the-future follies. Comments?

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 10:54 AM, Brendan Eich wrote:

But what if one could write this instead?

<altscript src="new.js" type="application/ecmascript;version=6"> <script ...> </script> </altscript>

Then we could have no round trips and fallback in the <altscript> container. This would entail no syntax errors, no extra round trips (beyond what current best practices motivate), and no freeze-the-future follies. Comments?

One comment I forgot (sorry, twitterific of me):

The fallback content, <script ...>...</script> could be inline or out of line (use src= in the first ...). However, the altscript tag would have to use src= and so its only script content would necessarily be out of line.

Fixing this is possible too, if I can take liberties:

<script-if type="application/ecmascript;version=6"> // new.js inline-exanded here </script-if else> <script ...> </script> </script-if end>

but now I'm hacking outside of HTML and SGML, with this if/else/end structure. Perhaps there is a more standard way to do this (a marked section? ugh).

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 11:09 AM, Brendan Eich wrote:

Fixing this is possible too, if I can take liberties:

<script-if type="application/ecmascript;version=6"> // new.js inline-exanded here </script-if else> <script ...> </script> </script-if end>

In case some on es-discuss are not up on HTML and browser implementations of it, this would fall back on the <script ...></script> content in old browsers, because the </script-if else> looks like an end tag for <script-if type=...>. The fallback content is then processed as not in any container (in this example). The </script-if end> is a stray end tag, ignored.

New browsers that understood this mock-syntax (I'm not seriously proposing it, just sketching) would extend HTML parsing and processing to drop the content between the </script-if else> and the </script-if end>.

Again the goal would be no-extra-round-trips-with-fallback-for-pre-Harmony-(or-pre-any-version) browsers.

# Jeff Walden (14 years ago)

On 10/14/2010 08:29 AM, Brendan Eich wrote:

Thus there is already one bit of opt-in versioning state in ES5, which must be carried from direct eval's caller to callee.

SpiderMonkey currently does this, but fairly shortly (I have patches) it will not. The eval function's implementation will always perform indirect eval, and only the eval opcode will perform direct eval. (We could statically distinguish strict+direct from non-strict+direct, too, with a separate opcode, but since it's trivial to query the currently executing script's strictness, runtime detection seems better than burning an opcode.)

That's only SpiderMonkey, of course, but as far as I can tell the concepts are applicable to any ECMAScript implementation.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 1:39 PM, Jeff Walden wrote:

On 10/14/2010 08:29 AM, Brendan Eich wrote:

Thus there is already one bit of opt-in versioning state in ES5, which must be carried from direct eval's caller to callee.

SpiderMonkey currently does this,

I wasn't describing any implementation, I was citing ES5 10.1.1, second bullet:

  • Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct call (see 15.1.2.1.1) to the eval function that is contained in strict mode code.

but fairly shortly (I have patches) it will not. The eval function's implementation will always perform indirect eval, and only the eval opcode will perform direct eval. (We could statically distinguish strict+direct from non-strict+direct, too, with a separate opcode, but since it's trivial to query the currently executing script's strictness, runtime detection seems better than burning an opcode.)

That's only SpiderMonkey, of course, but as far as I can tell the concepts are applicable to any ECMAScript implementation.

This is an implementation detail, independent of ES5 10.1.1 and unobservable unless there's a bug.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 11:15 AM, Brendan Eich wrote:

On Oct 14, 2010, at 11:09 AM, Brendan Eich wrote:

Fixing this is possible too, if I can take liberties:

<script-if type="application/ecmascript;version=6"> // new.js inline-exanded here </script-if else> <script ...> </script> </script-if end>

In case some on es-discuss are not up on HTML and browser implementations of it, this would fall back on the <script ...></script> content in old browsers, because the </script-if else> looks like an end tag for <script-if type=...>. The fallback content is then processed as not in any container (in this example). The </script-if end> is a stray end tag, ignored.

New browsers that understood this mock-syntax (I'm not seriously proposing it, just sketching) would extend HTML parsing and processing to drop the content between the </script-if else> and the </script-if end>.

Again the goal would be no-extra-round-trips-with-fallback-for-pre-Harmony-(or-pre-any-version) browsers.

I've been talking to Hixie (always stimulating! Also trying to get Maciej's attention.) My crazy not-quite-HTML sketching aside, the issue Ian and I are debating, at its best (ignoring any unknown syntax future-proofing proposal), is something like this:

Should autoconf[1] be the one true versioning approach for JS, syntax or semantics, as it more-or-less is for DOM API feature testing, etc.?

To be concrete, say you want to use 'let' in your code, and you have a Narcissus-based translator (maybe this will be a DoctorJS user script, a simple transform you can customize) to turn let into var and resolve any conflicts that might arise.

Hixie's suggestion is that you embed a boot-loader script that autoconf-tests:

<script> var haveLet = false; try { eval("let x = 42;"); haveLet = true; } catch (e) {} if (haveLet) loadScript("letbased.js"); else loadScript("varbased.js"); </script>

(loadScript does document.write of a script tag or whatever is fastest).

This is a mouthful of boilerplate to swallow, but it would work. Perhaps engines could optimize the eval("let x = 42;") -- eval on a string literal. In any event, this has the virtue of being backward-compatible, assuming a suitable loadScript implementation.

My response is to ask "can we not do better?"

Having to write this code, or copy/paste/correct it, is one cost.

Another is the runtime burned on this inline script tag, although that may well be noise on modern browsers and hardware.

A bigger cost is the generated loadScript runtime. Generated script tags can hurt. My goal with <altscript> or whatever it would be called is to get this generated script load back into markup, where it might be speculatively prefetched.

In principle I don't see what the problem is with extending markup. HTML long ago deviated from SGML and HTML5 is its own language. Languages are tools, they should evolve to serve their users.

Maybe there's a good reason why JS version selection with fallback must happen autoconf-style, in JS, with clumy boilerplate, and at the cost of a generated script load. I do not see it.

/be

[1] www.gnu.org/software/autoconf (thanks to dherman for this object-detection analogy/precedent)

# Maciej Stachowiak (14 years ago)

On Oct 14, 2010, at 2:54 PM, Brendan Eich wrote:

On Oct 14, 2010, at 11:15 AM, Brendan Eich wrote:

On Oct 14, 2010, at 11:09 AM, Brendan Eich wrote:

Fixing this is possible too, if I can take liberties:

<script-if type="application/ecmascript;version=6"> // new.js inline-exanded here </script-if else> <script ...> </script> </script-if end>

In case some on es-discuss are not up on HTML and browser implementations of it, this would fall back on the <script ...></script> content in old browsers, because the </script-if else> looks like an end tag for <script-if type=...>. The fallback content is then processed as not in any container (in this example). The </script-if end> is a stray end tag, ignored.

New browsers that understood this mock-syntax (I'm not seriously proposing it, just sketching) would extend HTML parsing and processing to drop the content between the </script-if else> and the </script-if end>.

Again the goal would be no-extra-round-trips-with-fallback-for-pre-Harmony-(or-pre-any-version) browsers.

I've been talking to Hixie (always stimulating! Also trying to get Maciej's attention.)

For what it's worth, I have noticed this thread, but have not had time to read it all and study the posts enough to give informed input.

My priors (before studying the thread closely):

  • I don't like modes.
  • If mode switching is necessary, I prefer in-band mode identification to external.
  • Harmony will effectively have three modes - Harmony (with all new syntax), ES5 strict + new Harmony APIs, ES5 non-strict + new Harmony APIs.
  • It seems per the current plan all three will have to be supported indefinitely. It's highly unlikely that currently deployed ES will all get replaced on anything less than geological time scalles.
  • Is the Harmony spec going to take responsibility for defining all three of those modes, or with the latter two just be implicit in the combination of the ES5 spec and parts of the Harmony spec? I would prefer if it took responsibility for fully defining all the modes, but it's not clear if this is the current plan.
  • Will we have to add yet another mode each time we add syntax? After enough iterations this becomes unsustainable.

I feel obligated to read the thread and think about it before proposing or evaluating specific solutions.

, Maciej

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 3:30 PM, Maciej Stachowiak wrote:

My priors (before studying the thread closely):

  • I don't like modes.

It will be simpler and shorten correspondence for those who do like modes to say so.

<crickets>

  • If mode switching is necessary, I prefer in-band mode identification to external.

Why is it either/or -- either in-band or not?

  • Harmony will effectively have three modes - Harmony (with all new syntax), ES5 strict + new Harmony APIs, ES5 non-strict + new Harmony APIs.

Nope. Harmony is based on ES5 strict. No 'with', no non-strict.

APIs can be object-detected, and overwritten if they have global bindings. But with simple modules this won't be an issue -- you'll declare what you need, loading from a built-in module resource identifier ("@std", "@dom", etc. -- these are straw anti-URI made-up names).

  • It seems per the current plan all three will have to be supported indefinitely. It's highly unlikely that currently deployed ES will all get replaced on anything less than geological time scalles.
  • Is the Harmony spec going to take responsibility for defining all three of those modes, or with the latter two just be implicit in the combination of the ES5 spec and parts of the Harmony spec? I would prefer if it took responsibility for fully defining all the modes, but it's not clear if this is the current plan.

We're responsible types around here, but your three needs to be lowered to two or one (with modules).

Seriously, we don't want a version lattice with bad combinatorics. We've been over this in TC39 meetings and there are records on the wiki. The prominent memento is 3(I) at:

harmony:harmony#means

  • Will we have to add yet another mode each time we add syntax? After enough iterations this becomes unsustainable.

Languages don't grow indefinitely but JS syntax (and semantics) are gappy enough there could be another edition that comes after the first Harmony edition. ES5, ES3, ES2.

This was far from unsustainable. The stagnation after ES3 was worse, frankly, and it did not prevail: de-facto extensions including new syntax, and the Web was better for it.

I feel obligated to read the thread and think about it before proposing or evaluating specific solutions.

Thanks.

# Brendan Eich (14 years ago)

On Oct 14, 2010, at 3:47 PM, Brendan Eich wrote:

Seriously, we don't want a version lattice with bad combinatorics. We've been over this in TC39 meetings and there are records on the wiki. The prominent memento is 3(I) at:

harmony:harmony#means

Prior to Means 3(I), there is Goal 4 (harmony:harmony#goals):

Keep versioning as simple and linear as possible.

We don't have concrete plans for a "use strict" in Harmony to opt into a "stricter than ES5 strict" mode. The "no more modes" plea is good as far as it goes (just not absolute), so I hope we do not add any such Harmony-strict-mode. We're really trying not to make an N-dimensional version/mode/pragma lattice.

But, again, ES5 makes incompatible (slight) changes to the de-facto standard JS ("ES3R") language, and ES5 strict is indeed a mode. New syntax is coming, but we will build it on ES5 strict under some kind of opt-in.

The minimum opt-in mechanism, we think, is specified by RFC4329: <script type="application/ecmascript;version=6">. This works in IE9, in the sense that the script tag content is not processed (thanks to Jeff Walden for testing). Testing in older and other browsers welcome,with and without the ;version= parameter.

Markup-based version selection, to allow inline, out of line (src=) with prefetching, and downrev-browser fallback without "autoconf-style" generation of script elements, seems worth considering.

  • Will we have to add yet another mode each time we add syntax? After enough iterations this becomes unsustainable.

Languages don't grow indefinitely but JS syntax (and semantics) are gappy enough there could be another edition that comes after the first Harmony edition.

That was a bit too neutral-sounding.

I want to add that my strong desire is to avoid adding syntax after the "Harmony edition" (let's hope it is ES6, but we have been burned picking numbers prematurely in the past, and there's no need yet to pick a number). I'm simply skeptical about our ability to predict the future or enforce a bad prediction.

Modules should give everyone writing libraries (least of all TC39) name-conflict-free upgrade paths, along with lexical scope all the way up (no global object). If we ever get to the promised land of macros, we'll need modules (and a lot else; macros are very much a dark horse, or just a gleam in my eye).

So modules are important. Proxies too. So are let/const/function-in-block. Some less critical but worthwhile conveniences matter too, enough that they're in the harmony section of the wiki.

If you ask me, the list outlined in the last paragraph is enough for "Harmony". I'm not sure we need classes or traits in the language; more work (under way) is needed to find out.

My two cents, and as usual I reserve the right to change my mind, or coins.

# Dmitry A. Soshnikov (14 years ago)

(At last I've read this thread; I'll answer not for this exact letter, but in general).

So, there are two backward compats issues:

  1. Running an old code (with possible naming conflicts such as let, const, etc) in a new (ES6) engines; thus, there is no new syntax involved;
  2. Running new code in the old engines (the issue with a new syntax).

For the first sub-problem a use harmony; directive can be enough. This also will work in non-browser host environments (such as CommonJS / Node.js).

However, in a view of exactly a pragma directive (i.e. not as a "use strict"; string literal) it will cause the second issue, i.e. a syntax error in all browsers (just right at the first line because they won't be able to parse this pragma). But, being in the "use harmony"; view (as a string literal) also won't solve the issue. Because old browsers even if won't fail on the first line, will do it later when find a new syntax (because the code will be ran anyway).

So for exactly old browsers the approach with:

<script type="harmony"> </script>

seems good (if not the only possible) since this block won't be even parsed/executed.

And for server-side JS -- there the approach a little different: the same the new code in old engines won't work -- syntax errors (and seems there are no other obvious ways to prevent it besides checking the MAX_ES_VERSION and require(...) dynamically needed code). But more likely, on the server side it's cheaper and easier to update the engine which support the new syntax (thus, even "use harmony;" isn't needed

# Dmitry A. Soshnikov (14 years ago)

P.S.[2]: also it seems I missed something, can someone clarify -- are let and const are removed from Harmony proposals since they shouldn't appear in ES5-strict (in the recommendations for implementations as I see) and since ES6 will be built on ES-strict?

P.S.[3] @MarkMiller: just a small (off-topic) clarification: do new Object.getPropertyDescriptor and Object.getPropertyNames consider in addition prototype chain or start lookup from the first object in the prototype chain? Because I need to implement JS shim for these two things and seems I understood not correctly e.g. Object.getPropertyDescriptor which doesn't consider own properties, but starts its analysis from the first object in the prototype chain.

# Dmitry A. Soshnikov (14 years ago)

On 18.10.2010 14:47, Dmitry A. Soshnikov wrote:

P.S.[2]: also it seems I missed something, can someone clarify -- are let and const are removed from Harmony proposals since they shouldn't appear in ES5-strict (in the recommendations for implementations as I see) and since ES6 will be built on ES-strict?

Sorry, got it. "Do not extend strict mode with declarations or statments using the keywords |const| or |let|" means do not allow use them as simple variable names, 'cause they are reserved for ES6.

Dmitry.

# Mark S. Miller (14 years ago)

In addition. The lookups start with the own properties of the objects in question.

# Dmitry A. Soshnikov (14 years ago)

Thanks (that means I implemented it wrong before, will fix).

Dmitry.

# Mark S. Miller (14 years ago)

On Mon, Oct 18, 2010 at 6:47 AM, Dmitry A. Soshnikov < dmitry.soshnikov at gmail.com> wrote:

P.S.[2]: also it seems I missed something, can someone clarify -- are let and const are removed from Harmony proposals since they shouldn't appear in ES5-strict (in the recommendations for implementations as I see) and since ES6 will be built on ES-strict?

No. We recommend that ES5/strict implementations reject 'let' and 'const' for now, so that there's no established divergent semantics by the time we codify their harmony semantics. Once there harmony semantics are adequately settled, proceeding to implement them in ES5/strict would be fine. Likewise with nested named function declarations.

# Dmitry A. Soshnikov (14 years ago)

On 18.10.2010 17:54, Mark S. Miller wrote:

On Mon, Oct 18, 2010 at 6:47 AM, Dmitry A. Soshnikov <dmitry.soshnikov at gmail.com <mailto:dmitry.soshnikov at gmail.com>> wrote:

P.S.[2]: also it seems I missed something, can someone clarify --
are `let` and `const` are removed from Harmony proposals since
they shouldn't appear in ES5-strict (in the recommendations for
implementations as I see) and since ES6 will be built on ES-strict?

No. We recommend that ES5/strict implementations reject 'let' and 'const' for now, so that there's no established divergent semantics by the time we codify their harmony semantics. Once there harmony semantics are adequately settled, proceeding to implement them in ES5/strict would be fine. Likewise with nested named function declarations.

Yep, also thanks, I already got it too (just was confused with a formulation).

Dmitry.