Whats wrong with JavaScript 2.0

Waldemar's work on the  JavaScript 2.0 ECMA-262 R4 Proposal while carried forth with good intention takes JavaScript, in my opinion, in entirely the wrong direction. JavaScript, a light high level programming language with a prototype based object model, has become extremely popular and is one of the most widely used languages in the world today. However, it's design was in many peoples opinions excessively minimalist and not geared toward large manageable code bases. Fortunately for all of us, the trends of the web have taken a turn for the better, and interactive, more demanding web applications are quickly becoming the norm. However; this introduces many questions of how to make JavaScript the language really hold up to these demands without the need for large crutch frameworks for managing extensions. JavaScript 2.0 was an attempt to address this, but it also attempted to address many other things that did not need to be addressed, to the general detriment of JavaScript.

Why Detriment?

Many of the features proposed in JavaScript 2.0 are largely unnecessary and were really brought to the table in order to stop poorly informed complaints about the language. That is, engineers who were accustomed to other environments (herein deemed "Java Weenies") thought felt JavaScript would benefit from being more akin to the environment they were accustomed to. This is largely untrue, and many of the features which were proposed as a result of the Java Weenies complaints are simply duplicate syntaxes for existing functionality, or unnecessary introduction of lower level constructs not fit for the level of abstraction of JavaScript.

Classes

This is probably the biggest and noisiest change proposed to be introduced into JavaScript 2.0, and in my humble opinion, one of the worst. JavaScript is a very object oriented language, and inheritably supports single inheritance (similar to Java!) but is missing a feature that would increase compile time safety (interfaces). The truth of the matter is JavaScript was designed as a runtime compiled programming language ("Scripting language"), and for this reason the requirement of compile time safety is entirely questionable. Great examples of other languages of the same runtime compiled class (Python, Ruby, AWK, Perl) of languages, many of them object oriented, also do not provide these safety contracts inheritly. Incoming objects must be explicitly checked. This feature exists in JavaScript currently.

So in short, classes are object descriptions that allow declaration of private data, a constructor method, and an inheritance chain. JavaScript has these, objects are built only by calling constructor functions, private data exists from lexical closures, methods can in turn be added in a prototype or in at compile time, and inheritance can be created by utilization of prototypes (defining an object as a prototype inherits that object, in JavaScript, objects are inherited not classes, but you can define inheritance chains quite easily this way). Not only does JavaScript not need classes, but introducing them will provide either misconceptions or inconsistency within it's object model. And adding a thin layer of syntax because you don't like the current syntax sends us right down the road toward PHP, and no offense to you PHP fans out there, but I think it's best of JavaScript stays small and simple.

Type Constraints

  • JavaScript
    function Constructor (example) {
        if (example.constructor != Constructor) {
            throw new InvlaidArgument("Invalid argument!")
        }
    }
    
  • Perl
    sub new {
        my ($type, $example) = @_;
        if (!$example->isa($type)) {
            die "Invalid argument!";
        }
    }
    
  • Python
    def Constructor:
        def __init__ (example):
            if (isinstance(example, Constructor))
               raise error "Invalid argument!"
    
  • Ruby
    class Constructor
        def create (example)
            if (example.class == Constructor)
                raise "Invalid argument!"
            end
        end
    end
    

Why do we need them? We don't. They aren't required, although I'm not convinced they are a terrible idea. They just aren't required. Alot of other great languages at this level of abstractions omit them. And since we don't have a compilation process, adding the overhead of this checking to the runtime compilation adds only arguable benefit.

Namespaces and packages

First off, there is an inherent problem with introducing both of these. They are different answers to the same problem. Namespaces in C++ are used to separate code, in order to eliminate the potential of namespace conflicts. This feature also exists in Perl, under a different name, packages. The similarity is that in Perl, packages use the same name space separator as C++. Packages in Perl, however, are slightly more magical, and we wont talk about that now. Java decided to omit namespaces, and introduce a concept called a package, uses the same character for name space separation as it uses for method dereferencing. This is the fundamental difference. Even the JavaScript 2.0 proposal doesn't create a clear distinction between namespaces and packages, and it doesn't have any rationale for introducing both syntaxes either. Adds inconsistency.

Now let's look at the existing JavaScript solution for namespaces - and it does exist, but it's not really needed and I'll talk about that in a minute. Simply, object members are dereferenced, hiding a constructor function behind a namespace is simply a matter of making it a member of an object.

var cfn = { /* cfn = clever framework name */
    Foo: function () {
        this.method = function () { .. }
    },
    Bar: function () {
        this.print = function () { print() }
    }
}
var example = new cfn.Foo()
var example = new cfn.Bar()

As you can see by the above example, some people might not consider this the most elegant solution. But in reality, it's perfectly sufficient. Now, let's talk about why we don't really need namespaces at all. If you look at the top of any Java application, you will see at least a dozen "import" statements. These statements are used to import classes into the local program, so their definitions could be used in short hand in the current class. With this in mind, maybe another anti-namespace cluttering mechanism should be considered.

Consider this behavior, which introduces an environment friendly slightly more implicit feature addition to JavaScript.

directive use quoted string

A use source directive, parsed at compile time, invokes compilation and execution of the relative script located at the supplied location, or, populates the current global object with all references declared in the script at this namespace, in the case in which it has already been parsed and compiled.

This behaves quite similarly to Perl's use statement but rather than translating namespace declarations to a package/file mapping, follows a syntax that is already existing in JavaScript without largely changing the language. It does introduce a new fundmental concept to JavaScript, however, that all separate script files will have a new global object. This isn't a very tricky new feature, though, as the script's local object could easily use the global object as it's prototype.

Now while that does provide a feature that Java Weenies are against, the ability to pollute global namespaces, JavaScript was designed for the ability to arbitrarily populate the global scope, as it is a scripting language designed for embedding and isolated environments. This is what JavaScript is good at, and this is why JavaScript is popular today. If it wasn't for the ability to stuff the "document" object into the namespace of the JavaScript code running in your browser, nobody would be using JavaScript today. We shouldn't loose sight of that.

Primitive Types

Okay, I have two very simple and clear reasons not to introduce primitives to JavaScript. And let's start with the purist reason (yes, you heard me, purism); JavaScript is Object Oriented. Primitives are quite simply not object oriented. One thing that Java Weenies don't realize is that primitives are one of the number one things standing between Java and being a completely object oriented language. In JavaScript, absolutely everything is an object. Even most literal expressions (numbers being the exception) have methods, and are instantly objects. And even then, a literal once assigned to an identifier is an object. Everything, literally everything, is an object. Functions? Objects. Classes? Hah! We don't have them, we start with Objects. Introducing primitives to JavaScript removes it's status of being purely object oriented. All of a sudden, not everything will be an object any longer.

Now for the other very important reason, consider the above statement the reason from the standpoint of language design, and this one, the reason from the standpoint of langauge implementation. JavaScript's level of abstraction does not harbor optimization of system level types. That is, in languages that have primitives (like C) you are close to the hardware. And even in Java, you are often in a JIT compilation engine that builds close-to-hardware types for primitives, and this offers optimization. There isn't a reason to do this in a dynamic language like JavaScript. It has no benefits.

Modifiers

Well these are some of my favorite, because JavaScript 1.6 (an extension of the existing ECMA-262 R3 specification) already has a form of them as they are defined in the JavaScript 2.0 specification. Although currently, JavaScript 1.6 only has two modifiers, and I believe they should be adopted by the specification because they are relatively useful. The most fundamental of those is the const declaration which defines a variable as constant. I find this useful, as since it's a simple value, it's easily optimized during runtime compilation by replacing each instance of a variable defined as const with it's value. This being in mind, const is fundamentally different from final in Java.

Here, in the JavaScript 2.0 recommendation, you can clearly see the influence Java Weenies have had on the proposal.


final
This class cannot be subclassed
const
This value cannot be changed

Now in Java, final means both of these things. There is no const. I don't see any reason for adding the inability to extend classes in funky, unconventional ways. In fact, if you look at some of the great Perl modules on CPAN, this very behavior has been the success of languages at the level of abstraction of JavaScript. They have high turn around, because they don't impose these large source code creating constraints. Want to change the way a module works? That's easy in Perl. Want to change the way an object works? That's easy in JavaScript. Want to change the way a class works in Java? Oh shoot, it's final. We have to:

  1. Crack open the source (bad!)
  2. Just rewrite it our own way (expensive!).

It becomes clear really quick, why this class of language has survived. It's also clear why this class of language may not be suited for things like extremely high traffic mission critical applications in large institutions (enterprise). Is Perl an good solution for a multibillion dollar investment firm's account management software? Well...probably not. But will it work for the *interface* layer? Why yes. And can we use it for periodic systems maintenance tasks that interact with the more refined implementation of account management functions? Yes! This is what JavaScript fits in, also. It's been most notoriously deployed as the interface layer of all Mozilla applications. And it's really, really good there. Easy to change. Quick turn around. Not set in stone.

There are other modifiers that aren't needed in JavaScript, and I'll go over them a little less indepthly.


final
See above
dynamic
JavaScript isn't a class based object model, and it shouldn't be.
internal
This would be no longer required if the above mentioned extension mechanism was in place. Additionally, if you really need a feature like this, check out how the grease monkey developers have dealt with it (it's a little funny, "var" inside an anonymous function that is executed rather than referenced means that it lives in a scope that only lives as long as that function and all of the things it creates). Also, if the semantics of var were slightly changed, then this entire concept wouldn't be needed.
enumerable
I don't even think I should waste my time talking about this.
explicit
If we don't have packages, we don't need this. And if we do have packages, we still don't really need this.
private
JavaScript already has private data, it's private by virtue of enclosure. We don't need classes, so we don't need this keyword.
protected
I realize this was only in discussion, but what the heck are you guys thinking?

In fact, I won't even continue defining these. Quite simply, all of these are just not needed because JavaScript was designed to be an abstract high level language. Only Java Weenies want to make it more like Java and less like "Scripting languages". Being a "Scripting language", or runtime compiled language doesn't mean being bad, or hard to manage, it means being flexible. Being less bound to rules is great for code that is typically very hard to write with very low ROI, such as extensions of existing applications, user interfaces, and so forth. These are all the great uses of JavaScript that have made it as successful as it is today. Why are we trying to take it in the direction of a language niche that is in no shortage of solutions?

Pragmas

Now pragmas introduce a great feature to JavaScript, that isn't currently needed but speaks of an interesting topic I would like to go into more depth about.

Pragmas are lexically scoped and their effect does not extend past the end of the enclosing block, directive group, or substatement group.

Now, lexical scoping I think would be a useful addition to JavaScript. Function level scoping causes people to do funny things, like the below example you will find in grease monkey scripts:

(function () {
    var private_array = []
    var foo = function () {
       /* do something with private_array */
    }
    document.getElementById("x").addEventHandler("click", foo)
})();

If JavaScript had complex lexical scoping, meaning var would live no longer than the current programme block, where a programme block is a group of statements between curly brackets ( { } ) then this would actually inheritly eliminate the requirement to do this, and provide slightly tighter memory management for JavaScript. But, in the same argument, the current model is very simple to implement. So I suppose I will leave that as an open discussion. But with the above mentioned items already ruled out (in my mind atleast), some of the reasons to introduce pragmas are eliminated. The JavaScript 2.0 proposal suggested them for compatibility with JavaScript 1.5, but if we don't change the language much, we can easily eliminate the need for them. However, if we introduce a feature like lexical scoping, they will be needed in order to declare that lexical scoping will be used. Otherwise, obviously, old code will break. Although, in most cases, the old code won't break. In most uses, the function scoping behavior of var isn't properly understood and thus, it's not used to it's most undesired capacities.

Another thing

People continuously complain about the optional semi-colons in JavaScript. But what we really need are not to eliminate them, but to make a generally accepted practice be the norm. Python has optional semicolons, and no one complains about them there. AWK also shares this feature, in fact Brenden was hardly the first langauge designer to put this in a language. My proposal is that we strongly suggest against the use of semicolons, in a nice high profile documented manner. The rationale for suggesting against them is that there are many defiant programmers out there (such as myself) who will opt not to use them, because I'm a fan of concision and I don't like unnecessary punctuation. If JavaScript works fine without the extra punctuation, which it does (In over six years and hundreds of thousands of lines of code, I've had only one case of ambiguity bite me in the rear, and I was doing something really strange), then it should just be omitted.

We shouldn't decide to require them because Java does, because in the same light we could just as easily decide not to require them since Python and AWK, and who knows what else, don't require them.

Summary

  • JavaScript does need a better extension mechanism
  • We don't need to change the language much
  • JavaScript doesn't need to look like Java, or any other language
  • JavaScript is supposed to be high level, abstract, and flexible. This is why it's been good, and it should continue to be used the way it currently is. It's good at it, and if we change the language in the way suggested by JavaScript 2.0, honestly we'll need to create another JavaScript to fill the need it has successfully fulfilled.
  • JavaScript already has most of the features people complain about not having, in ways that aren't really that ugly or intrusive, despite popular belief.

Comment by iSkitz on Wed May 31 06:04:24 2006

Excellent examination of this topic. What will it take to have this view adopted by those defining and implementing JavaScript?

Comment by scott on Wed May 31 16:24:54 2006

Interestingly enough,  Brenden Eich, (CTO of the Mozilla Foundation, and designer of JavaScript) has already read this material and has made a relatively formal response in the form of quoting several of these statements and attempting to address them in talks he gave at  The Ajax Experience and  XTech 2006.

 Slides can be found here.

The slides, unfortunately, do not have the full context of the talk, but they provide a few hints as to what we can expect for the future of JavaScript.

Unfortunately, it seems like I lost the class argument.

Comment by anonymous on Mon Jun 5 12:03:59 2006

spam removed

Comment by cdonat at gmx.de on Wed Jun 7 14:56:34 2006

I am very much for the use of the semicolon. The reason is simply that the Interpreter can not reliably distinguish Statements which are on one line without semicolons. Every JS-Packer I know cuts out newlines and thus relies on the semicolons. Especially with larger JS-Code a Packer can reduce the download time to an acceptable measure.

I support all your other points.

Comment by scott on Wed Jun 7 19:11:29 2006

Code packers are not something I'm concerned with. Code packers should insert missing semicolons where neccesary when removing newlines from source code (Although, newline is exactly the same size as semi-colon. So removing new lines and inserting semi-colons saves you nothing). If a code packager removes newlines and does not insert the necessary semi-colons then it's broken.

Comment by cdonat at gmx.de on Sun Jun 11 12:42:30 2006

The point with code-packers is not just that they remove characters. They compress the code, write it to a string and add a small routine to uncompress and eval() it again. As i said it can save you quite an ammount of bandwidth for larger JS-applications.

Why don't these packers insert semicolons where needed? Well, simply because that is not so easy. You would have to write a JS-parser to really find out where a semicolon is needed. That parser is more complicated and slower than a simple routine that collapses multiple spaces outside of strings.

I don't say that you have to use semicolons everywhere. That is simply not my business. It is just that removing semicolons from the language removes the possibility to write the whole code into a single line. Thus that would break most existing code-packers which quite some people rely on.

Comment by scott on Sun Jun 11 19:40:14 2006

I never suggested removing them from the language. I suggested making omitting the semi-colons the common convetion, similar to python. In langauges like Python, and AWK, semi-colons are actually optional. However the common practice in python is to omit the optional semi-colons, up until the point where some people don't even realize they are in fact optional.

I suggested that in order to hush the complaints regarding optional semi-colons, we the javascript community adopt a smiliar practice.

Comment by anonymous on Sat Jul 15 16:21:26 2006

I agree to most of your positions, except that I would rather recommend using semicolons (as I would have made them required if I had designed the language).

It is indeed pretty deceitful to read some of those JS2.0 proposals. JavaScript should definitely remain as flexible as it currently is, allowing to dynamically add properties/methods to any object or their prototype objects, with everything remaining an object.

Spam

I've had to close this thread due to abuse.