Close review of Language Overview whitepaper

Brendan Eich brendan at
Wed Nov 14 17:34:37 PST 2007

Hey Maciej, thanks for the detailed comments. As many detailed  
responses as I can muster below -- all opinions mine unless noted  
(e.g. where I cite a group opinion).

On Nov 14, 2007, at 2:03 PM, Maciej Stachowiak wrote:

> Goals: I strongly agree with the stated goals of compatibility and
> enabling large software development. I wonder if perhaps performance
> should be added as a goal. At the very least we want it to be possible
> to achieve performance on par with ES3 engines, and ideally we want to
> enable better performance.

I know of proofs that much better performance (order of magnitude  
over latest interpreters) is coming to JS1 implementations, so I  
think this is a red herring. It would be good to avoid anti- 
performance mandatory changes, of course -- that might not be obvious.

> Programming in the small: "... make the writing and reading of
> fragments of code simpler and more effortless." That is somewhat
> dubious gramatically,

English crit, watch out! ;-) I did not write this, but I'll leap to  
the author's defense. The grammar's fine and usage manuals  
(Partridge, Fowler -- if memory serves) allow "more effortless". See  

First hit:

> I suggest (with additional style fixes) "make
> the reading and writing of code fragments easier."

I like your suggestion, though.

> Portability: This section first it says that the full language must be
> supported - subset profiles are not desirable. Then it says that, to
> allow ES4 to be practically implementable on small devices and in
> hosted environments, certain features, like extensive compile-time
> analysis and stack marks cannot be part of the language. Then it says
> those features are part of the language, but optional.

Clearly the overview should distinguish between mandatory standard  
mode features and optional strict mode and reflection features.

But you have a point about optional reflection features being useless  
on the web, so what's the point? One answer is to have a normative  
spec, so where support exists, the implementations can interoperate.  
This may not be enough for reflection -- it depends on likely uptake.  
We think it is enough to justify strict mode. More below.

> Syntax: The new non-contextual keywords, and the resulting need to
> specify dialect out of band, are a problem. I'll have more to say
> about compatibility under separate cover.

We've talked about this before, and I'm looking forward to your  

I would hope we can avoid having to do what we believe should be post- 
ES4 standardized AST, reader, and even macro work, just to allay  
concerns about ES4->ES5. We can't do all that work before ES4, but of  
course we want to make next time better. I noted on IRC that adding  
the 'x' flag to regexps, and codifying how IE handles / in a  
character class in a regexp (which browsers have had to follow), both  
break by-the-book ES3 scanners.

> Behavior:
> - This section has says that "variation among ES3 implementations
> entails a license to specify behavior more precisely for ES4".
> However, the example given is a case where behavior among two
> implementations was already the same, due to compatibility
> considerations. I actually think both convergence on a single behavior
> where variation is allowed, and variation that leads to practical
> compatibility issues are license to spec more precisely,

We do not want to overspecify, however. The majority of those who've  
expressed an opinion in TG1 do not want, e.g., to specify Date.parse  
as it is implemented in any given browser, never mind finding the  
intersection among all browsers.

> - The RegExp change - is this really a bug fix? It's likely that this
> is not a big compatibility issue (Safari's ES3 implementation had
> things the proposed ES4 way for some time) but I think ES3's approach
> may be more performance and generating a new object every time does
> not seem especially helpful.

This bug is the second most duplicated among bugs filed with's bug system since 1998:

Full dup-count available at 

sort by Component for best results.

This singleton pigeon-hole problem hurts users all the time (I get  
mail from individual developers confused by it, at least once a year).

The performance worry for the proposed ES4 fix of evaluating a regexp  
literal to a new object, just as is done for other mutable objects  
expressed literally, is not an issue in our experience. Just as the  
compiler precomputes invariant parts of function objects, so it can  
memoize regexp constant parts, and wrap a mutable object around the  
shared immutable innards on each evaluation.

Quality implementations do this for function objects already, and  
some do it for regexps too, in order to support executing a  
precompiled script in several execution contexts (possibly  

> Is there any significant implementation that anyone would claim is
> 100% free of ECMAScript 3 compliance bugs?

No, and that's a good thing!

> I doubt it, and so I think
> we should make this section less judgmental in tone.

Agreed, thanks for pointing this out. I certainly missed it (everyone  
has bugs; some bugs are just problems in an implementation to fix,  
and we need not ascribe them to inadequate engineering practices, or  
blame darker motives for that matter :-/).

> Wrappers: The whitepaper implies that providing catchall getters and
> setters for primitive types and skipping boxing isn't a compatibility
> issue. However, it is possible in ES3 to capture an implicit wrapper:
> var x;
> String.prototype.myFunc = function() { = "foo"; x = this; };
> "bar".myFunc();
> Prototype hacking allows you to observe identity of the temporary
> wrappers, save them for later, and store properties. Perhaps there is
> evidence that practices relying on techniques like this are
> exceedingly uncommon (I'd certainly believe it), if so it should be
> cited.

This was a bug to fix, which I brought up too late to be included in  
the overview. See

We believe this is fixed now, but please comment there if you see a  
problem still.

> Literals:
> - I am surprised to see a decimal type (a type that is not directly
> supported in current mainstream hardware) even though generally
> popular types like single-precision IEEE floating point and 64 bit
> integers are not present.

See the third most duplicated bug in

See also the "Apple Flunks First Grade Math" blog post, I kid you  
not, here:

I am sure on this basis you will agree with our inclusion of decimal  
in ES4 :-].

> Even when the final
> result cannot overflow, certainly in many expressions the difference
> between int and double intermediates can be observed. It seems likely,
> then, that math on variables declared int will be slower than math on
> variables declared double, which will surely be confusing to
> developers.

Are you sure integer ops with well-predicted overflow guards are  
slower than FP ops? I have contrary evidence and know of some papers  
in submission on this that suggest it is not a problem. But some of  
these papers also show the advice in favor of annotating :int to  
"improve performance" to be bad advice.

In other words, I'm disputing your contention that it's likely let  
i:int loop control variables will be slower than let i:double -- but  
I'm also saying that I think let i may be as fast as the faster of  
the annotated forms in ES4-as-proposed, on some of the forthcoming JS  
VMs. Performance is a red herring, again. To be demonstrated!

> Record and array types: Structural types are confusingly similar to
> yet different from classes. Mostly they offer a subset of class
> functionality (though reading ahead I did see a few features limited
> to them). Also, already having prototype-based objects and class-based
> objects it seems excessive to add yet a third way. I recommend
> removing them and adding any features that are sorely missed as a
> result to classes.

You miss the main difference: structural types are not equated by  
name, so they avoid the inheritance trap of classes, which consists  
of building hierarchies deriving from non-final nominal types  
(classes and interfaces) that constrain the evolution of the base  
types; or else slapping final too much on base classes (especially in  
the standard library).

Structural types formalize the "duck typing" done in ES3 code on the  
web. Most such code will never be retrofitted to use nominal types,  
but with structural types for API parameters, along with 'like' and  
'wrap', duck-typed data from such code can flow into typesafe libraries.

This is a crucial use-case, and perhaps the overview needs to spend  
more time on it. It's not something I (at least; also the majority of  
the group working on ES4, I think) will give up easily.

> "Any": The spec explains vaguely that the "any" type is not identical
> to the union (null, undefined, Object). How is it different? Is the
> difference observable to ES4 programs or is it purely a matter
> internal to the spec (in which case the difference is not relevant)?

Did you see footnote 17? It's a formality, perhaps not worth  
burdening the overview reader with, though.

> "wrap": Seems like a version of this feature and/or "like" founded on
> classes would work just as well.

Not so -- consider retrofitting existing code that passes objects and  
arrays, in JSON-like trees, to Ajax library APIs. We do not want to  
require all the library-client code to be rewritten to use nominal  
types. We should not prefer nominal types anyway, since they do not  
scale to the web due to the base-class pigeon hole problem I  
mentioned above, which leads to overconstrained class hierarchies  
over time, or else the final keyword prohibiting derived classes in  
the first place.

> Conversions: "In addition, any value in the language converts to a
> member of AnyBoolean", but the conversions specified are all to the
> more specific "boolean" type, so perhaps it should be expressed that
> way to avoid confusion.

I thought this too, when reviewing this section. I think this is an  
open issue, but I can't find a ticket for it. I'll follow up.

> Binding objects and scopes: It seems like introducing lexical block
> scopes makes things more challenging for online implementations.
> Creating a dynamic scope object per block scope is clearly
> unacceptable, but more work may be needed to build a per-function
> symbol table that can properly accomodate block scope.

Shipped in Firefox 2. It was Not Hard ;-).

> Is block scope
> worth it? Yes, "var" is a little weird, but having both "var" and
> "let" increases conceptual footprint and may overall lead to more
> author confusion.

Block scope is important to those larger-scale programs you favored  
early on. We have experience from Firefox 2 on supporting this, as do  
others who've extended ES3.

> package: Now that I have learned more about them, I think that
> exposing packages and namespaces as separate user-level concepts is
> confusing. Let's get this down to a single concept that developers
> have to learn.

As I noted in a previous thread, I'm sympathetic...

> Namespaces can just have a paired internal namespace
> implicitly,

... but not to this proposal. A namespace should not be two  
namespaces in disguise. I'd rather defer packages altogether from ES4  
than double namespace costs and remove their primitive utility (which  
ES4 relies on heavily).

> I do not think it is helpful to give the public/internal
> pair a special different name.

It is definitely not helpful to double the cost of namespaces just to  
cover package's use-cases.

> Program units:
> - Is there any need for the concept of "unit" to be exposed in the
> syntax? Why not just allow "use unit" at top level, and implicitly
> make each file (or in the browser context each inline script) a unit?


for examples including server-side expansion and client-side caching  
of units, independent of how they are stored in files or transported  
in HTTP responses.

> Versioning: I am suspicious of versioning mechanisms, especially big
> giant switch versioning. Is there any use of __ECMASCRIPT_VERSION__
> that is not better handled by feature testing? (Maybe there is and I
> am not thinking of it.)

Two points:

* Feature-testing in multi-version languages and libraries, in my  
experience at least, has produced more implicit version combinations  
against which to measure and support compatibility, than a total  
version order, ideally a number line.

* We expect users to write in the new language and transcode to the  
old using offline or just-in-time source-to-source translators. Such  
systems want whole-language versioning, not feature tests.

> arguments: It seems strange to both deprecate a feature and improve it
> at the same time.

Deprecation via strong language in specs is worth the paper it's  
printed on, IMHO. You need carrots as well as sticks. Rest params are  
the sweetest carrot, but arguments will endure, and already Opera (at  
least) makes arguments delegate to Array. People want it, and it is  
easy and free of downside. Give the people what they want here :-).

> Strict:
> - I would strongly prefer if strict mode did not alter behavior of
> programs at all, except to reject those that do not pass the checks.
> Otherwise, since strict mode is optional, this risks interop issues.

The interop issue would be that standard mode runs a program that  
would fail at runtime with strict mode's eval change. Such a program  
must therefore make bindings in eval's dynamic scope. We can't have a  
sound strict mode without this change, and there may be others --  
Mark Miller has me convinced that a short list of runtime semantic  
changes (restrictions, exception-throwing) made by Google Caja are  
all necessary. More on this in due course.

See two responses below for more on why it's probably helpful to  
interop to specify an optional strict mode, once for all  
implementations that choose to support 'use strict'.

>  So I'm curious what the eval detail is. Perhaps strict mode could
> remove the eval operator and allow only the eval function, with some
> suitably named version made available ahead of time, if the difference
> is just removing local eval behavior.

It's not that simple The problem is the contents of the eval  
argument, which are not visible to strict mode or the compiler.

> - I am somewhat concerned about having strict mode at all. It seems
> like it could create the same kinds of problems we see today with
> content that is served as application/xhtml+xml to some browsers and
> text/html to others. It's not infrequent to see such content break
> only in the browsers that really support XML, due to sloppy testing of
> changes and the fact that the 78% browser doesn't support XHTML.

We see this problem from the other side. There are numerous competing  
"lint-like" tools, and some optional type checkers in JS-derived  
languages. These will tend to produce interop bugs with greater  
frequency in the absence of a normative strict mode spec (optional at  
each implementation's discretion) than if there were such a spec for  
strict mode. So we are specifying. If an ES4 implementation supports  
'use strict', it must follow the spec.

> Verification:
> - Does strict mode actually allow for any optimizations that couldn't
> be done to the exact same program in standard mode?

IMHO strict mode has nothing to do with optimizations.

> Section IX.
> "switch type" statement: I guess this beats switching on typeof, but
> is it really significantly better than a series of "if" statements
> using the "is" operator?

And lexical bindings for the types cracked by the cases? Yes.  
Consider typed exception handling vs. a single catch clause with an  
if/else chain or switch (and the obligation to re-throw in the else  
or default -- which users forget).

You're right that switch type, like destructuring assignment, is  
sugar. We are providing sugar. It reduces code size, improves  
readability, and eliminates bug habitat. Its cost in practical JS  
parsers, based on Firefox 2 and other experience, is in the noise.

> Expression closures: I actually find the examples hard to follow given
> my expectation of ES3-like syntax. I think this may actually be
> syntactic salt.

Implemented in the RI, and in Firefox 3 beta. Based on the experience  
of people using these, it's sweet, sweet sugar -- but tastes vary. My  
only thought is to urge you to use expression closures in your own  
code, and give them a chance to grow on you, before rendering final  

> Semicolon insertion: I'd like more detail on the compatibility of the
> return change.

The return change was withdrawn. See

> Reflection: This feature seems like it could be complex to implement
> and potentially unnecessary for small implementations. I note that
> J2ME omits reflection, which we can perhaps take as a sign that it is
> not suitable for small implementations.

Or blow bronx cheers. :-P Sorry, but citing J2ME is fighting words to  
me, and proof of nothing in particular.

> JSON: Sounds good.

This proposal is withdrawn and another API is being considered for  
reinclusion later. See http:;//

> Things I didn't see:
> What about standardizing the de facto <!-- comment syntax that is
> necessary for web compatibility?

Please write the spec ;-). Don't forget the --> mess.


More information about the Es4-discuss mailing list