13 June 2005

JavaScript 1, 2, and in between

With DHTML and AJAX hot (or hot again; we’ve been here before, and I don’t like either acronym), I am asked frequently these days about JavaScript, past and future. In spite of the fact that JS was misnamed (I will call it JS in the rest of this entry), standardized prematurely, then ignored and stagnated during most of its life, its primitives are strong enough that whole ecologies of toolkit and web-app code have emerged on top of it. (I don’t agree with everything Doug Crockford writes at the last two links, but most of his arrows hit their targets.)

Too many of the JS/DHTML toolkits have the “you must use our APIs for everything, including how you manipulate strings” disease. Some are cool, for example TIBET, which looks a lot like Smalltalk. Some have real value, e.g. Oddpost, which Yahoo! acquired perhaps as much for its DHTML toolkit as for the mail client built on that toolkit.

Yet no JS toolkit has taken off in a big way on the web, probably more on account of the costs of learning and bundling any given API, than because of the “you must use our APIs and only our APIs” problem. So people keep inventing their own toolkits.

Inventing toolkits and extension systems on top of JS is cool. I hoped that would happen, because during Netscape 2 and 3 days I was under great pressure to minimize JS-the-language, implement JS-the-DOM, and defer to Java for “real programming” (this was a mistake, but until Netscape hired more than temporary intern or loaner help, around the time Netscape 4 work began, I was the entire “JS team” — so delegating to Java seemed like a good idea at the time). Therefore in minimizing JS-the-language, I added explicit prototype-based delegation, allowing users to supplement built-in methods with their own in the same given single-prototype namespace.

In listening to user feedback, participating in ECMA TG1 (back during Edition 1 days, and again recently for E4X and the revived Edition 4 work), and all the while watching how the several major “JS” implementors have maintained and evolved their implementations, I’ve come to some conclusions about what JS does and does not need.

  • JS is not going away, so it ought to evolve. As with sharks (and relationships, see Annie Hall), a programming language is either moving forward, or it’s dead. Now dead languages (natural and programming) have their uses; fixed denotation and grammar, and in general a lack of “versionitis”, are virtues. You could argue that JS’s stagnation, along with HTML’s, was beneficial for the “Web 1.0″ build-out of the last decade. But given all the ferment on the web today, in XUL and its stepchildren, and with user scripting, there should be a JS2, and even a JS1.6 on the way toward JS2.
  • JS does not need to become Java, or C#, or any other language.
  • JS does need some of its sharp corners rounded safely. See the table below for details.
  • Beyond fixing what was broken in JS1, JS should evolve to solve problems that users face today in the domains where JS lives: web page and application content (including Flash), server-side scripting (whether Rhino or .NET), VXML and similar embeddings, and games.
  • For example, it should be trivial in a future version of JS to produce or consume a “package” of useful script that presents a consistent interface to consumers, even as its implementation details and new interfaces evolve to better meet existing requirements, and to meet entirely new requirements. In no case should internal methods or properties be exposed by default.
  • It’s clear to me that some users want obfuscated source code, but I am not in favor of standardizing an obfuscator. Mozilla products could support the IE obfuscator, if someone wants to fix bug 125525. A standard obfuscator is that much less obscure, besides being unlikely to be adopted by those who have already invented their own (who appear to be the only users truly motivated by a need for obfuscation at this point).
  • A more intuitive numeric type or type tower would help many users, although to be effective it would have to be enabled via a new compile-time option of some sort. Numeric type improvements, together with Edition 4’s extensible operator and unit proposals, would address many user requests for enhancement I’ve heard over the years.
  • Too much JS, in almost every embedding I’ve seen, suffers from an execution model that appears single-threaded (which is good for most users) yet lacks coroutining or more specific forms of it such as generators (Boo has particularly nice forms, building on Python with a cleanup or two). So users end up writing lots of creepy callbacks, setTimeout chains, and explicit control block state machines, instead of simply writing loops and similar constructs that can deliver results one by one, suspending after each delivery until called again.

That’s my “do and don’t” list for any future JS, and I will say more, with more specifics, about what to add to the language. What to fix is easier to identify, provided we can fix compatibly without making a mess of old and new.

Here are the three most-duplicated bug reports against core language design elements tracked by Mozilla’s bugzilla installation:


Bug #

Dupe
Count


Component

Severity

Op Sys

Target
Milestone


Summary
98409 6 JavaScript Engine normal All literal global regular expression (regexp) instance remembers lastIndex
22964 55 JavaScript Engine normal All JavaScript: getYear returns “100” for 2000
5856 15 JavaScript Engine normal Windows 98 javascript rounding bug

I argue that we ought to fix these, in backward-compatible fashion if possible, in a new Edition of ECMA-262. If we solve other real problems that have not racked up duplicate bug counts, but fail to fix these usability flaws, we have failed to listen to JS users. Let’s consider these one by one:

  1. Unlike object and array initialisers, and E4X’s XML literals, regular expression literals correspond one-for-one with objects created during parsing. While this is often optimal and even useful, when combined with the g (global) flag and the lastIndex property, these singleton literals make for a pigeon-hole problem, and a gratuitous inconsistency with other kinds of “literals”. To fix this compatibly, we could add a new flag, although it would be good to pick a letter not used by Perl (or Perl 6, which fearlessly revamps Perl’s regular expression sub-language in ways that ECMA-262 will likely not follow).
  2. The Date.prototype.getYear method is a botch and a blight, the only Y2K bug in Mozilla-based browsers that still ships for compatibility with too many web sites. This bug came directly from java.util.Date, which was deprecated long ago. I’d like to get rid of it, but in the mean time, perhaps we should throw in the towel and emulate IE’s non-ECMA behavior (ECMA-262 did standardize getYear in a non-normative annex).
  3. The solution here is a new default number type, with arbitrary precision and something equivalent to decimal radix. Mike Cowlishaw has advocated and implemented his own flavor of decimal arithmetic, but it is not popular in ECMA TG1. Still, I bet we could make life better for many JS users with some innovation here.

There are other bugs in JS1 to fix, particularly to do with Unicode in regular expressions, and even in source text (see the infamous ZWNJ and ZWJ should not be ignored bug). More on these too, shortly, but in a wiki, linked with informal discussion here.

/be

44 Responses to “JavaScript 1, 2, and in between”

  1. Jeff Walden says:

    Man, that “standardized prematurely” link is really pretty bizarre. Some parts of it seem reasonable and more or less in line with what I understand of JS (global object and function.length vs. function.arguments.length being two such items), but I can’t honestly conceive of any reason to even consider other parts (like the whole section where he advocates pretty much throwing out the whole idea of Reserved Words). Why in the world would you want to allow variables named ‘var’, ‘while’, or ‘function’ (and even worse, make those functionalities dead in the current scope)? The same goes for his operator proposals along the lines of +=, *=, etc. except with the boolean operators &&, ||, etc. The usefulness of this approaches nil, as you really don’t see them used much outside of conditional expressions.
    As for the future ideas, I think looking into ways to include code from outside the current file is something worth doing. CSS can import other CSS using @import. C/C++ have #include to pull in code from elsewhere. Java has import. To the best of my knowledge, tho, there’s nothing similar in JavaScript. People have been doing document.write(“<script src=’…’) hacks for a while now, but that only applies in HTML-like, non-XML environments. I’d really be interested in seeing some way to import code from outside the current source and evaluate it. (This of course assumes I haven’t missed this feature somewhere in current specs, but I very much doubt I’d have missed something as useful as this could be.)
    Anyway, I’m done rambling now. Keep up the posts!

  2. Brendan Eich says:

    Jeff: we reserved all of Java’s identifiers (Java 1 or whatever it was back in ’95), and ECMA-262 also reserves a good chunk of the same words, but not all the ones Mozilla’s C engine (SpiderMonkey) reserved. This led to bug 240317.
    Doug’s point is that if we can reserve fewer words, why reserve any? Then the trick is to make error reporting and recovery as good as would be the case with reserved identifiers.
    It’s easier for language implementors to simply reserve some words. But if it could be made no worse for users to unreserve those words, why not? If someone wants to name a function “switch”, and that function is never called in the left-most part of a top-level expression statement, then there’s no ambiguity.
    Too late for ECMA-262, but I’ll ramble back at you ;-).
    The item where I talked about producing and consuming a package implies some kind of import mechanism, in the language. How the package name maps onto a filename, or a member in a .jar file, may be peculiar to the JS embedding, and so not standardized.
    /be

  3. Adrian D. says:

    >> I’d really be interested in seeing some way to import code from outside the current source and evaluate it.
    Potentially, via the DOM, document.createElement(“script”) could be used…
    Here’s my ideas for the future :)
    I’d like to see a wider range of date strings available when creating a date. Eg, to be able to do new Date(“2005-06-13″), or even new Date(“3 days ago”).
    Also, setIntervals/Timeout chains are pure, pure hell because you can’t specify a non-global object as the function’s argument. Eg you can’t do:
    animateEl = function(el){
    this.animate = function(){
    /*animation code here */
    setInterval(“this.animate()”, 50)
    }
    return this
    }
    I think this could be solved with a pause()… like so
    this.animate = function(){
    while(){
    /*animation code here */
    pause(50)
    }
    }
    Some other nice things would be String.trim(), String.md5(). Also, this may be the realm of the DOM, but it would be good to be able to “pre assign” events to elements before they have loaded. Event attributes in X/HTML are clumsy to work with.
    Thanks for listening!

  4. Brendan Eich says:

    I wanted to add that I don’t agree with Douglas Crockford’s suggestion that using a currently-reserved identifier as a formal parameter name (e.g.) should disable the meaning of that word in context within the function. Rather, the parser would look for reserved identifiers only in certain contexts (at the beginning of a statement, e.g.). Ok, I’ll stop beating this dead horse now.
    Adrian: you can pass a |this| parameter to setTimeout or setInterval, but it requires a helper function:
    setInterval(function (t) { animate.call(t); }, 50, this);
    Notice that the first arg is a function reference, not a string. This may not be well-known, but in combination with Function.prototype.call (or .apply) and extra trailing args to setInterval (or setTimeout), it does the job.
    /be

  5. The beauty of Javascript is that additional methods like String.trim() and String.md5() can easily ba added to the existing prototype via your own script library.
    Standardizing some of these might of course be a nice thing, but more important would be to make that methods can also be added to the Object and Array prototype without breaking for/in loops. Like through implementing…
    dontenum Array.prototype.contains
    …as recommended by Douglas Crockford in the page mentioned above.

  6. Jean Devefre says:

    Please don’t make getYear IE compatible. Sure, bug 22964 has a high dupe count but if you look closely most reports after 2001 came from JS beginners who were probably working without any reference or using outdated books/tutorials. OTOH, code like the following still seems to be widely used on real web sites (google for it):
    if (appName == “Netscape”) year=1900 + year;
    I’d bet this change would cause a flood of new bug reports about web sites showing the year as 3905.
    Unfortunately IE uses a variant of setTimeout/setInterval where the third argument specifies the script language. This is even the currently recommended variant in WHATWG’s Web Application spec.
    Lastly, here is another vote for some way to set DontEnum. Couldn’t this be achieved backwards compatible with a new Object.prototype method, e.g.
    foo = { baz: 1 };
    foo.dontEnum(‘baz’);

  7. Bryant Chen says:

    I’ve been looking at the ECMAScript 4 and JavaScript 2 proposals and it’s confusing the hell out of me. Since you’re the creator of JS (although you apparently aren’t responsible for JS2), let me ask some questions concerning JS2.
    1) What is the include/import mechanism in JS2? It looks like include and import were in the proposal but then dropped: “Put back a very simple package definition/import mechanism. Moved the extended import directive with the include/exclude selection mechanism to the rationale.” But then the package section states: “Packages were originally part of the ECMAScript Edition 4 proposal but have been removed due to time constraints.” So what exactly is the current import mechanism?
    2) Since functions now support typed parameters, can they be overloaded?
    Jean, there’s currently an enumerable keyword in ECMAScript 4, though it seems like it can only be used class definitions: “The default for dynamic properties and class properties is enumerable. The default for instance properties is non-enumerable. There is no way to make a user-defined dynamic or class property non-enumerable.”

  8. Peter Wilson says:

    I’ve been using SpiderMonkey for about 5 years now embedded in our own server-side environment. I’ve written a number of complex JS applications based around our environment. My guidance/suggstions on the way forward for JS would be to keep it simple, keep it fast, keep it small.
    I’ve not looked at JS2 for a good while, but my impression at the time was that it was trying to be C++/Java. I think that is the wrong direction – but probably the result of a design by committee.
    Keeping it simple: I think I’d argue that even E4X is too complex. The core language allows you to do everything you need to do to process XML without bloating the core engine further. Not only that – many environments already have full XML processing libraries and so that code is now duplicated.
    Keep it fast: Speed in a browser environment isn’t a huge issue, but server side JavaScript is just so much beter than PHP – but in that environment you may have 100 instances of JavaScript running concurrently. Don’t overload the engines with run-time checks just to become a ‘grown-up’ language.
    Keep it small: Again in a server environment size is important. Don’t bloat the core language with things that *could* be placed in a library everything to implement a #include equivalent is already there. You have a proprieatry function to load the source followed by an eval().
    My personal view is that the core language is now basically there bar some tweaks. That should then form the bedrock of core libraries that can be layered on top. I could make a number of ‘useful’ enhancements to a specific implementation such as SpiderMonkey, but those are nothing to do with the language.

  9. tag says:

    ES4 is bothersome in its current state. JavaScript (which I will from here on refer to as “ES”) has been a shining example of use of a unique object model that works. Adding classes to the mix only creates inconsitency, and makes the language more like just every other language. I think the language would benefit more from a more traditional inheritance mechanism (extension provided by adding a “inherits” method or similar to the Function prototype for describing inheritance chains of constructors) rather than creating inconsistency (with a class object there is no Object.constructor, atleast in JScript.NET which seems to have already implemented much of the ES4/JS2/Spice suggestions [ in a less than adequate fasion ] ). I see no mention in these suggestions of how to handle the inconstincy that would be inherit of adding such a thing as a second object model to the language, and it appears to me to not create any benefit…really. The prototype object model is already perfect sufficient, if it hasn’t proved more flexible and possibly more powerful than the alternative model.
    As for ECMA-357, I have it in print, I’ve looked over it thuroughly, and it reminds me of AWK. E4X relies deeply on the current popularity (and current specification) of XML, which seems like a major pitfall that would force ES into a niche language category it would less than benefit from. (Even if XML is here to stay) The W3C has taken great consideration into building the DOM recommendation, and I think it is perfectly adequate for the job it needs to do. E4X adds a lot of syntax with very little advantage to ES itself, and seems like nothing other than shorthand for those too lazy to use the DOM API.
    I think ES would greatly benefit from operator overloading, and I think its presence is long over due. I believe a seperate mechanism should be created for adding operators in a prototype-kind of way. (Constructor.operator[] would make a lot of sense) I think all of this effort of adding things ES doesn’t need (classes, static types) would be better spent creating an appropriate, light, scalable development environment outside of client side web and desktop applications that would let us take advantage of how great ES already is already.

  10. tag says:

    As for Douglas Crockford’s notes I think he’s off his rocker. Not only does he provide no rationale for his suggesting deprecation of semi-colon insertion, the with statement, the comma operator, arguments.callee, or especially (what the..?!) typeof!
    Also last I checked new String () wasn’t a primative type wrapper.

  11. Brendan Eich says:

    Jean: you’re probably right, we shouldn’t change getYear at this point, unless we can somehow detect the IE dependency (as we did with undetected document.all uses, for Firefox 1.0/Mozilla 1.7).
    I’ve mailed Hixie about WHATWG specifying setTimeout and setInterval fully. When the first argument is a function object, the trailing arguments after the delay (wish I’d got the arg order right, but the function form came after the string) must be trailing arguments to the function.
    JS2 has an enumerable attribute, but that does not help JS1.x-ish script do what you want. So some kind of dynamic meta-object protocol hook seems necessary.
    We already have Object.prototype.propertyIsEnumerable (although that does not check for a prototype property, so it gives a different answer from what you would get from a for..in loop — why? I wasn’t in ECMA TG1 when this was added; if someone who was knows the rationale, please comment). So we could have another method to make a property non-enumerable.
    /be

  12. Brendan Eich says:

    Bryant: I’ll do my best to answer JS2 questions, but as you note, I didn’t design it. Waldemar did, and perhaps he will comment here.
    Packages are in flux in ECMA TG1 right now, but there will be ways to declare, extend, and import them. They were more like a namespace combined with an object in JS2, but they are looking more like Java packages in TG1, based on Macromedia’s input. That may change, so keep up the comments.
    Type annotations for JS were always designed with the principle (independently discovered by Python folks and called “Adaptation”, IIRC), that we want the meaning of a script not to depend on optional type annotations. Otherwise, it will be hard to impossible to mix JS1 and JS2 code where unqualified names are overloaded with only type annotations distinguishing the different meanings.
    Note that you can use namespaces to distinguish two properties of the same instance that have the same identifier: q1::id and q2::id.
    /be

  13. Jeff Walden says:

    Brendan:
    Jeff: we reserved all of Java’s identifiers (Java 1 or whatever it was back in ’95), and ECMA-262 also reserves a good chunk of the same words, but not all the ones Mozilla’s C engine (SpiderMonkey) reserved. This led to bug 240317.
    I prefer to look at bug 240317 as a problem with the script writers, who failed to familiarize themselves with JavaScript as compared to JScript. Aside from JScript’s extensions, there aren’t all that many differences between the two in simple functionality that’s worked in pretty much all browsers since the v4 days. This may not be very pragmatic, but I think a little education is the most correct fix. (Since we’re talking about the Java keywords here, however, I don’t think I’d be opposed to removing the Java-only, non-ECMA-262 reserved words from the list. Keeping them as reserved does preserve that choice, even if un-reserving reserved words isn’t what happens to most reserved words.)
    Adrian:
    Potentially, via the DOM, document.createElement(“script”) could be used…
    This presupposes that there’s a document object and that there’s a DOM through which things are happening, making this suggestion just a slightly cleaner syntax for the document.write hack. As an example, you can write scripts for the Windows Scripting Host in JScript, which is based off JavaScript, and I don’t think you have access to either document or the DOM in such scripts.

  14. Bryant Chen says:

    Brendan, thanks for the answers.
    I have a couple of suggestions concerning the spec. Not sure if this is the right place to put them, but I’ll say them anyway.
    1) Determine the currently valid use cases eval, and provide alternative functionality to cover as many as those cases:
    1a) Getting the value of an identifier in function scope from a string that resolves to that identifier:
    function foo() { var a = 0; debug(‘a’); }
    function debug(str) { alert(str + ‘: ‘ + eval(str)); }
    1b) Introducing (actually copying) an out-of-scope function into scope:
    function debug() { alert(str); }
    function foo() { var str = ‘hello'; eval(debug.toString()); debug(); }
    Note: this is not related to importing a namespace’s objects. If anything, it would be related to importing objects into the current namespace.
    1c) Interpreting script code that’s dynamically generated (e.g. getting the code via XMLHTTP) – no alternative suggested here.
    2) Since classes can only be defined “compile-time”, constructor/prototype functions, which aren’t restricted to compile-time, should also allow private/public attributes. I would like this to work:
    function foo() {
    var x = 10;
    return new function() {
    private var i = x;
    public function method(y) { return i + y; }
    }
    }
    Specifically, private would be the default, while public is the equivalent of “this.property = something”. Functions should also include an implicit “use namespace(FunctionPublicF)” so that the this object doesn’t have to be used to access public properties.
    This would help further differentiate compile-time and run-time statements.
    Compile-time: classes, function definitions (in strict mode)
    Run-time: prototype functions, function expressions
    3) There needs to be an easier way to create an anonymous inner scope. Currently, you have to do this:
    (function() {
    //do stuff
    })();
    4) Currently, setTimeout and setInterval are properties of the DOM, not JS. I’m not sure if it would be a good idea to import these DOM methods into the JS core.
    The time management model definitely needs to be improved though. A pause() or wait() function would do wonders. However, they somehow need to be asynchronous. For example, suppose we have this:
    while (cond) {
    box.style.left = (parseInt(box.style.left) – 100) + ‘px';
    wait(5000);
    }
    This would be useless if the wait function prevented execution of any other function during the wait, or, even worse, paused the browser. After all, this is why nobody uses “wait hacks” like “while ((new Date()).getTime() != some_time);”.

  15. Brendan Eich says:

    Bryant: point by point, briefly:
    1a) If debug is a scripted function like any other, it has static scope, so its eval(str) which tries to eval the identifier |a| will not find the local variable in function foo’s activation, which calls debug(). Since debug is not dynamically scoped, your sketch can’t work as written. But I was not sure that you meant debug to be a scripted function, or a new native method akin to eval, but more limited (accepting only an identifier named by a string argument?).
    1b) Can you point to a real-world example?
    1c) That’s eval.
    2) We can’t change the JS1 defaults in non-strict mode.
    In any event, the nested function named |method| is not a property of the |this| instance being “new’ed”, according to JS1 rules. And making a nested public function in JS2 does not cause its name to bind in the *instance* created by the enclosing constructor.
    3) Agreed. The JS2 and ES4 proposals under http://www.mozilla.org/js/language/ include block scope, AFAICT.
    4) See this blog entry, where I talk about coroutines and generators. Of course we cannot have busy-loops. Nor do we wish to introduce preemptively scheduled multi-threading hardships (whether via software concurrency or hardware parallelism).
    Yielding cooperatively, on the other hand, does not add too much to implementors’ burdens, and make life much nicer for state machine implementors: they can use normal data and control flow instead of writing explicit state save and restore code at every transition that might need to yield.
    Pausing for a certain number of milliseconds can be done using coroutines too, but there would not be any preemptive scheduling. Other coroutines would have to yield soon enough, though, to give the paused one a chance to resume on or near its deadline.
    This too is not so much of a stretch for JS, since JS’s apparently-single-threaded execution model in the browser has so far required “run to completion” without hogging the CPU.
    /be

  16. Bryant Chen says:

    1a) Sorry, bad example. Debug should’ve been an inner function:
    function foo() {
    function debug() { alert(eval(x)); }
    var a = 10;
    debug(‘a’);
    }
    1b) Scratch this one. I remembered I used this technique before, to avoid specifying parameters over and over again. I just realized that it could also be done with closures, even with functions that have no parameters:
    function debug() { alert(x); }
    function foo() {
    function debug() { window.x = x; window.debug(); }
    var x = 10;
    debug();
    }
    Of course, the better way would be this:
    function debug(str) { alert(str); }
    function foo() {
    function debug() { window.debug(x); }
    var x = 10;
    debug();
    }
    2) I’m not suggesting changing any defaults for JS1. JS1 treats vars within function scope as local to that function scope, so they’re already private. For reference, this is what it would be in JS1:
    function foo() {
    var x = 10;
    return new function() {
    var i = x;
    this.method = function(y) { return i + y; }
    }
    }
    I know that the public here is currently meaningless in JS2, but I think this should be a special exception.
    3) Found the section concerning that: http://www.mozilla.org/js/language/es4/core/statements.html#N-Block
    However, I was under the impression that that would cause conflicts with object literals with respect to the parser. For example:
    ({ foo: function() { alert(10); } }).foo();
    No one in their right mind would do something like this, but this is currently valid in JS1. Would this work in JS2?
    4) Good to hear :)
    Now for some new questions:
    5) Does the global object have a environment-independent identifier now? The changelog states “Defined the global object, namespaces, attributes, and classes” but I can’t find the definition anywhere.
    6) Can the getter and setter functions be directly accessed? For example, something like this:
    var x;
    function get foo() { return x; }
    var fooGet = get foo;
    On the flip side, can this be done:
    function fooGet() { return x; }
    get foo = fooGet;

  17. jsmarr says:

    It would be great to add a logging console to JavaScript (something akin to System.err.println) because once your JavaScript webapps get complex (particularly with DHTML/AJAX), adding alerts and window.status = myvar just doesn’t cut it any more. Since mozilla has a JavaScript console, a simple built-in function that would log there would be a big step forward. Then you could even do some simple code profiling by logging timestamps in parts of your code. JavaScript is definitely being used as a “full blown programming language” and so the lack of corresponding tools like debugging, logging, profiling, etc. is getting more and more painful. Of course that’s a compliment to the usefulness of JavaScript, but some better development infrastructure would be a huge help and can’t all be hacked in from outside. Thanks! js

  18. ajs318 says:

    What really, really bugs me about JS is the way it uses the “+” operator for concatenating strings. This all but means you can’t add numbers, for fear that one or other will be read as a string and the operation will turn into a concatenation.
    Example:
    if (document.theform.nm.value < 59) {
    document.theform.mn.value += 1;
    };
    doesn’t increment the number in “mn” as you would exxpect; it concatenates the string “1” to the end. This is highly counter-intuitive!
    I realise that BASIC used + to concatenate strings, but there was a difference: BASIC did not freely mix number and string types. It was obvious from context {speech marks around string literals, dollar signs on the ends of string variables} whether one was operating with strings or numbers.
    If you’re going to treat numbers and strings as a single scalar type, you can’t rely on context alone to determine which is which. There is a reason why Perl and PHP use different operators for these different operations!

  19. I hacked quite some JS the last two years, and there are certain things I would like to see changed in or added to the core, too (some dupes in here):
    * operator overloading would be *very* useful (notably . and [], those would not only allow you to elegantly add datatypes with complex behaviour, but also do things like implement multiple inheritance and such)
    * there should be an operator to test if a variable is in use (currently it’s not possible to see whether a variable has a value undefined, or whether it just doesn’t exist)
    * [] should resolve to false imo (way more intuitive, if the previous point would be implemented it would even be possible to do the same for {}, although I think that might not be so nice since {} creates a generic object and not a specific container type)
    * richer interfaces for core datatypes would improve consistency of libraries/modules (I wouldn’t mind losing e.g. String.prototype.blink() for a String.prototype.strip() for instance!! The problem with not providing such basic stuff is that people will implement them themselves, sometimes with different behaviour, resulting in libraries that can not be executed in the same namespace.)
    * a proper way of importing libraries would be nice, *and preferrably not in the global namespace!!*
    * I find the ability to call methods in a context outside of the object it’s defined on (this) very nice, but it should never be used in the core and/or DOM (seems to be the most common mindbreaker for newbies, and is never really useful since references to the new context can always be obtained in another way (e.g. through Event.target))
    * a dedicated keyword for class definition would be nice too (I don’t think there’s a usecase for being able to use a constructor as a normal function, is there?)
    * a dedicated base class for exceptions, preferrably with a mechanism to get stack traces on it, would probably make writing solid code easier
    (and I could go on a bit more, but perhaps then I’d give away that I just wrote too much Python code… ;)
    Now I understand that some of these changes have too much impact on a widely used language, but just wanted you to know my thoughts anyway, figured they might be nice material for discussion…
    Having said that, thanks for providing us with such a cool, dynamic, pragmatic language! It can be quirky at times, but gets the job done, and usually quite painless…

  20. Patrick Geiller says:

    Use a closure to fix the setInterval problem :
    animateEl = function(el){
    var _this = this;
    this.animate = function(){
    setInterval(_this.animate(), 50)
    }
    }
    It avoids adding a third member to setInterval. I use a lot pointers to members and wish there was a simpler way.( &this.animate() ? )

  21. Patrick Geiller says:

    Woops. I meant
    setInterval( function () { _this.animate() }, 50).

  22. Brook Monroe says:

    Like Bryant Chen, I find it extremely helpful to use SpiderMonkey as an inner scripting language; in some cases, I simply couldn’t have accomplished some programming projects without it. (I keep thinking that I’ll write a Solaris or Linux shell based on JS, but hope that someone has already done it contributes to my laziness, so I haven’t done it yet.)
    I’d like to go on record as opposing operator overloading in JS. The amount of abuse it gets in C++ is reason enough, IMHO, but beyond that, I see it as a performance sink. As much as I like the idea of JS being a general-purpose language, if you’ve found tasks that require operator overloading in a script, it might be you need to defer to some server-side compiled code to get the job done for you. (In a non-web environment, that might not be possible, and I’m in no way suggesting the addition of JSNI. Not me. That way lies madness.)
    Lots of people have plenty of reasons for wanting operator overloading, but I’d just like to see the performance aspects investigated before we jump in head first….

  23. jbot says:

    What would be nice in JS2 would be the option to compile the code into DLLs much the same way that you can do in JScript.NET. We could then run XUL-based applications which have clientside business logic, without having to resort to Zend-encoded PHP deployed with the application. Now, that would be sweet.
    Also, what are people’s thoughts on Whitebeam Serverside JS?

  24. ptw says:

    Dylan gets by with only [7](http://gauss.gwydiondylan.org/books/drm/drm_117.html) reserved words. There are many other names exported from the Dylan module, but they can all be shadowed. The Dylan macro system permits this power. That system has been applied to [Java](http://portal.acm.org/citation.cfm?id=504285), and could be applied to JS.

  25. Tom Trenka says:

    I hate to hop on a bandwagon suggesting improvements to something like this. However, that being said…
    I completely agree with you Brendan about not modifying JS in a major way at all; I think that despite the good efforts of JS2, it will never fly or be fully accepted as a lang only because it moves JS out of the simple scripting territory and into the strongly-typed language territory. That being said, having been a hardcore JS developer (among many other things) for quite some time, there are a few things I would kill for:
    1. Operator overloading (this would rock, even though we can somewhat pull it off with careful use of native methods of the Object)
    2. Standardized getters and setters. The version implemented in Moz is not bad, but iirc it’s only implemented in Moz, right?
    3. Byte array handling. I know this one may seem like a silly request, but there have been a number of situations (including dealing with streams, like a truly raw TCP/IP request/response stream) where I really could have used something a bit more robust than treating an Array object of numbers as a byte array.
    Other than that, I would really object to any other modifications…well, maybe some sort of threading would be great, although I would prefer to not have that take the form of setTimeout/setInterval.
    And I completely agree about the trend to write all-compassing APIs by DHTML developers :)

  26. Adrian D. says:

    Thanks for the tip Patrick, seems to do the trick….. except I think you were meaning to use a setTimeout in the example as that code quickly spawns a flood of multiplying setInterval’s :)

  27. Heron says:

    If a major version of JS will come out (1.6 or 2.0), why not grab the opportunity to rename it?
    I vote for JoyfulScript. No java, same abbreviation (JS) 8)
    And it looks like it’s not taken yet.
    8)

  28. Tom Trenka says:

    Hmm…I’ve read Doug’s suggestions before, but now after reading it again, I think most of them are really bad ideas…I think the only things I agree with are the readonly and sealed modifiers, and probably the reflection on a function object.
    Thinking about it more, I think I’d probably like to see just a little bit more exposure of the prototype object as well.
    As I reflect on your post more though Brendan, I keep returning to the conclusion that the majority of the issue here isn’t the language; it’s the material available for people to learn it, as well as the fact that it truly is misunderstood…

  29. There’s another way to call an object’s member function in a setInterval or setTimeout call. You have to create a bind() member on the Function object’s prototype first:
    Function.prototype.bind = function( object )
    {
    var method = this;
    return function()
    {
    method.apply( object );
    }
    }
    Then you can “bind” a member function to a setTimeout call like this (assuming your object has a method named foo):
    setTimeout( this.foo.bind( this ), 50 );

  30. Bill Burdick says:

    Rhino currently supports continuations, which nicely provides you with coroutines and all sorts of other useful functionality. Is anyone looking at this for JS proper?

  31. Brendan Eich says:

    Peter Wilson: JS should not become C++, and the JS2 draft spec does not make that mistake. Waldemar worked hard to preserve dynamism and first-class types (types as parameters, e.g.). However, he definitely is of the “MIT” school (I’m of the “New Jersey” school — see http://www.jwz.org/doc/worse-is-better.html). JS2’s classes follow from the opinion that classical inheritance trumps prototype-based delegation.
    I agree that JS should remain “small”. This may put me at odds with others on ECMA TG1 who have already invested in implementing much of Waldemar’s spec (with some changes and divergences).
    tag: I’m not sure what you mean by “last I checked new String () wasn’t a primitive type wrapper”. It is, in JS1, which was a result of too much Java influence combined with laziness on my part back in the 1995 mad rush for Netscape 2. JS2 should do away with this “boxing”. Everything’s an object, as Smalltalk (should have) taught us.
    Certainly, Douglas Crockford gets a few things wrong, but he is right that typeof is fairly broken. typeof null == “object”? What was I thinking? We should have fixed this in ECMA-262 Edition 1.
    Bryant: again, I’ll minimize reply overhead and cite your numbers:
    2: JS2 has declarative forms for methods, which are not inner functions. We shouldn’t mix the two up, or overload one’s syntax for the other in certain modes or contexts.
    3: Object literals (initialisers) are ambiguous given block statements in JS1, never mind whether block statements define scopes. The ambiguity is resolved by treating a left brace at the start of a statement as the beginning of a block, not an initialiser.
    5: The global object has always been |this| at top-level, and that continues. I don’t know of a proposal to add a synonym. New names risk collision, and may be overridden by inner scopes anyway. Better to capture |this| in a global variable that you name.
    6: SpiderMonkey has Object.prototype.__lookupGetter__ and .__lookupSetter__, but AFAIK, JS2 has no syntax or meta-object protocol for getting getters and setters given their ids. Perhaps it should.
    Adrian D.: I mailed Hixie and he replied saying he’ll fix WHATWG’s setTimeout/setInterval place-holder spec to detail trailing args for the “funarg” forms.
    The problems with |with| are documented at http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:with.
    jsmarr: great points, I hope someone finds or files a bug (cc: me if I’m not on it) about enhancing the JS console as you propose. I’ve heard recently from Nat Friedman that too many JS developers cut their teeth on IE using MSDN docs, so don’t know about the console, or Venkman, or the DOM inspector. Hard to believe.
    We certainly should do more. Axel Hecht has rekindled the Eclipse-based XUL IDE project that I pitched in a Mozilla Developer Day in early 2004. Anyone know how that effort is going?
    More replies in a bit.
    /be

  32. Ian Bicking says:

    I’d love to see some very minimal updates to the language in response to people’s development experiences (not so much in response to making Javascript more like another language). The problems I’ve encountered:
    * Imports. I think “a_library = import(‘location’);” would be an easy way to implement imports. This would find the code — relative to the current Javascript location, not the browser location! — evaluate it in its own global space, and return that space. I don’t even think you’d need to change the language.
    This would be very similar to Python’s “import foo as a_library” but, IMHO, even easier and more reliable (since it wouldn’t try to divine names based on files).
    * Some of Douglas Crockford’s ideas are very sensible. Too bad Reserved Words is at the top of that document, since it doesn’t seem like a very popular idea. Otherwise they are all sensible. The multitude of is* operators strike me as a little odd (and I assume they are intended to replace typeof), but still reasonable.
    * I don’t think operator overloading is that important. I think most people would be happy with simple (standardized) getter and setter methods, but they think of that as operator overloading. Something like Python’s __getattr__ and __setattr__, or Smalltalk’s doesNotUnderstand (i.e., only called when a property isn’t found).
    I think some other proposed changes to the language are people reacting to pervasive problems of bad style and technique. As Javascript becomes increasingly relevent and sophisticated, I believe documentation, commentary, good examples, and communication can solve these problems. I hate when customers try to get me to solve their internal communication problems with code; in turn we shouldn’t ask the language to solve the community’s problems developing good practices in Javascript.

  33. Hi, Brendan.
    I got here from slashdot.
    Some years ago I had the urge to implement an ecmascript interpreter by myself (called ‘see’), so that I could get a text-based web browser to understand a proxy-autoconf file. It was an enjoyable exercise at the time. In the interop tests against spidermonkey i even submitted some obscure testsuite bugs to mozilla.
    Anyway, when implementing the js runtime, the biggest hurdle i faced was unicode support! the unicode standard seems to move about faster than i wanted to keep up with. i never found a simple enough unicode library to my liking, so it hurts me to this day.
    Also, I think the xml literals in the newer js are very cool. I would love to see XPath (or something better) as part of the language.
    Thankyou for inventing JS.

  34. I totally agree with Ian that a huge issue currently is lack of documentation and community infrastructure. There is some documentation out there if you start looking, but it’s really hard to find good patterns and guidelines for developers and such, and no code repositories and whatnot to make that people actually share code and libraries (sidenote: I think JavaScript is not very well suited for sharing code, since it’s not very easy to avoid polluting the window namespace and/or overriding stuff on base prototypes). It would imo really imprve the quality of the code and knowledge out there if there was a single location where developers could meet, share code and ideas, and find documentation and news and such… (Of course this is hardly a language update, so not entirely relevant for the topic, but I do think it’s an interesting subject and it would be nice if such an effort would be led by people that have an already established name in the JS world, not just some company somewhere or something).
    By the way, a small trick to get Ian’s import to work (although it only works on platforms on which both XmlHTTPRequest and eval.apply/eval.call are properly implemented, which excludes IE) is to load the data into a string, create an empty object (which will serve as namespace), execute eval.call(object, jsstring) and return the object…
    Anyway, nice thread so far, good to know things are on the move…

  35. The beauty of javascript is the extensibility. Many things are easier to do in javascript with the prototypes than in many other languages.
    I recently became interested in aspect oriented programming and javascript was probably the language with the lowest barrier. It makes AOP so easy because of the simple ways you have to extend and change the javascript objects.
    My experiment is described here: http://www.dotvoid.com/view.php?id=43

  36. AdolfoC says:

    “(this was a mistake, but until Netscape hired more than temporary intern or loaner help, around the time Netscape 4 work began, I was the entire “JS team” — so delegating to Java seemed like a good idea at the time)”
    Hey Brendan, I WAS that temporary intern. Of course, I’ll readily admit I wasn’t very useful back then. You were a darn busy guy.

  37. tag says:

    Brendan: Sorry my reply was a bit hasty or rather, not even proof-read. My main point was that in his suggestions Mr. Crawford seems to take the stance “Remove this, because I don’t like it”, particularly in the list which encapsulated the suggestion to remove typeof entirely.
    By primitive type wrapper you must mean, a constructor that returns an object which has equivilent function of the type with the same name. Which may be possibly what he was saying, which I may have misunderstood. If not, then it might need to be brought to someones attention that typeof new String (“”) == “object” && typeof String (“”) == “string”
    Maybe everything should be an object, I’m not going to get into that discussion.
    I am still trying to figure out why the JS2, ES4, and Spice notes introduce classes and typeclass restrictions. I understand there is an argument that “JS2’s classes follow from the opinion that classical inheritance trumps prototype-based delegation”, but I do not by any means agree with it. And as I have mentioned before the added inconsistency is nothing but a problem. The prototype object definition model was selected, and I don’t see how switching away from it have any benefit for the language.
    I will stand by my comments, after further review I continue to conclude the ES4 Proposal does little more than make a mess out of things as it currently stands.
    There are other less intrusive mechanisms for adding the features desired that would not break the language so fundementally. ES4 is trying too hard not to be ES, in my opinion. I really hope someone with some weight on the ECMA TG agrees with me on this. I’d hate to see another language ruined from design by committee.
    I think I’ll have to spend this weekend coming up with some more formal suggestions

  38. Lasse R. Nielsen says:

    Just a nitpick about the “eval.apply/eval.call are properly implemented” thing.
    IE is in compliance with ECMAScript v3, even if eval.call() doesn’t work. Implementations can choose *only* to allow calls to eval as a method of the global object (ECMA 262 v3 section 15.1.2.1).

  39. Peter Wilson says:

    Quick point in reponse to Ian Bickings first bullet : import.
    It’s easy to forget that JavaScript isn’t a browser only environment. JavaScript is used in many other applications, including server-side web applications but also as a generic scripting language for other products.
    ‘import’ requires no change to the language, it just needs those environments for which it is appropriate to implement an import function. Some environments won’t even have a concept of importing a file, others may want to allow imports by URL and others from a file-system.
    In the case of a browser there are plenty of other places that could standardise ‘import’.

  40. Hi, I just released a new asterisk pbx module that uses JavaScript and I thought Breandan would be interested since he’s refered to in the posting.
    Have a Little Talk, With JavaScript

  41. PeterWilson says:

    I have recently been experimenting with JASON to define Domain Specific Languages (a SPARQL processor) in which the language is directly executable as Javascript.
    A killer addition to JS would be named keywords and operator overloading. With these additions it becomes possible to define much more readable sub-languages when combined with a JASON approach. .
    Yes, I know the problems of operator overloading (Although the Nice language solves them) – but the class of languages that can be defined is much larger with operators than without.
    I’m sure you could think of other JS enhancements to facilitate DSL developement.
    b.t.w. I am a different Peter Wilson from the one above. Beware of impostors!

  42. mary says:

    Great post Brendan! I just read it and it

  43. Paul1 says:

    Java is the best language!

  44. Shanti Rao says:

    I would like to draw a distinction between what I think of as language features and conventions.
    Language features are things like the core objects, syntax features like E4X, and a threading model. Conventions depend on the particular implementation, like print(), alert(), and include().
    Some JS embeddings might have the stdin/stdout/stderr concept, so print() works for them. Other JS embeddings run without a file system, so a standardized include() is just going to cause trouble.
    So what’s my point? JS code may work across platforms, but not across embeddings. Not everyone agrees on what include() or print() should do, or whether it should be called print() or writeln().
    It would be valuable to have an agreement on what basic I/O functions should be called (if they’re available) and what they ought to do if they’re given a standard name.