JavaScript is Dead. Long Live JavaScript!

For 16 years, JavaScript has been the language of the web browser. This language has enabled the building of compelling web applications and contributed to the success of the web. Other scripting languages could have filled the role JavaScript does but JavaScript was in the right place at the right time. Microsoft added Basic to Internet Explorer a long time ago but JavaScript was the language in all the browsers and so it won. Since JavaScript has been cross-browser and at least good enough, the browser makers have not needed to add other language interpreters to the browsers themselves.

But we still didn’t choose to use JavaScript. It has been the one option. It has powerful features like closures and we learned to love these features while turning a blind eye to the warty parts of the language. There has even been a lot of apologizing to the programming community along the lines of “Yes we know it is a pretty funky language but please give it a chance. I’m sure you’ll learn to love it.” It shouldn’t be that hard to sell the quality of the language. JavaScript has been described as an experiment that escaped the lab a little too early and we’ve been stuck with the warts ever since.

Still, JavaScript has been a great language. In 2007, Steve Yegge declared JavaScript as The Next Big Language and it has been. Between then and now JavaScript-based web-applications have become bigger and better. With JavaScript’s help, the web has continued to flourish even with the threat of native mobile apps taking over the same space.

In very recent times, JavaScript has been making its most successful attempt at being a server-side language. The Node.js platform, with its non-blocking I/O, may be solving a problem that programmers have needed solved for a long time. JavaScript is the language for Node.js and so JavaScript may go along for the ride to become a successful server-side language after many failed attempts in the past.

Overall, JavaScript has been a wild success. The most popular programming language in the world. But if the browser died today, how much new JavaScript code would be written tomorrow? Most likely JavaScript would become a fringe language overnight. But the browser isn’t dying tomorrow. We will be programming for it for years to come.

As JavaScript has been used for more and larger programs, the warts of the language have become more apparent and caused increasing amounts of grief for many developers. It may come as a surprise that even though I’ve written about JavaScript for years, I’m not a JavaScript fanboy. Most of my JavaScript articles have been about me working through the difficulties of finding a peaceful coexistence with the language. Yes I’ve enjoyed programming in JavaScript and have learned a lot but there certainly have been times when I’ve felt like I’m wallowing in the muck.

One of the most obvious deficiencies in JavaScript is with its user interface: its syntax. The inability to quickly improve its syntax has lead to the language’s downfall.

The Case for Syntax Extensions: Verbose Idioms

Here we look at just four of the many examples where JavaScript’s syntax could be improved to remove verbose idioms from our daily programming existences.

Optional Parameters and Default Values

JavaScript functions can be called with a variable number of actual parameters. This makes some of the formal parameters in the function’s declaration optional. Often times these optional parameters must be set to a default value if no actual parameter is supplied. I’m willing to bet you’ve written and seen plenty of code like the following.

function(a, b, option) {
    option = option || {};
    // ...
}

I have and still write code like this. This code is wrong. If a falsy value is passed to the function for option then the wrong thing happens. We should be writing the following.

function(a, b, option) {
    option = arguments.length > 2 ? option : {};
    // ...
}

Although this code expresses the intended thought of setting a default value if an actual parameter for option is not supplied, it is too verbose and less readable. The reader must count to determine which variable is has index 2. Beyond the awkwardness, the correct version is more difficult to maintain. It is easy to produce the following buggy code if the b parameter is removed.

function(a, option) {
    option = arguments.length > 2 ? option : {};
    // ...
}

If your application uses optional parameters with default values, some new syntax would be beneficial for you.

function(a, b, option = {}) {
    // ...
}

The addition of this new syntax tunes the language better to your application’s needs.

Let

Does the following buggy code look familiar?

for (var i=0, ilen=elements.length; i<ilen; i++) {
    var element = elements[i];
    LIB_addEventListener(element, 'click', function(event) {
        alert('I was originally number ' + i);
    });
}

All the elements were the same number?! The solution is to use an immediately evaluated function expression so each alert reports a different number. This is the “let” idiom after Lisp’s various let forms.

for (var i=0, ilen=elements.length; i<ilen; i++) {
    var element = elements[i];
    (function(num) {
        LIB_addEventListener(element, 'click', function(event) {
            alert('I was originally number ' + num);
        });
    }(i));
}

Sure sometimes delegate listeners might be better than the above code but sometimes the above code is the desired idea. In the above case, we are trying to bind the order of the elements when the loop runs. This order could be lost with the delegate pattern if the elements are rearranged in the DOM.

This syntax is particularly awkward because of the distance between the formal num and actual i parameters of the immediate function.

The immediate function could be factored out to another location and called inside the loop.

function attachListener(element, num) {
    LIB_addEventListener(element, 'click', function(event) {
        alert('I was originally number ' + num);
    });
}
for (var i=0, ilen=elements.length; i<ilen; i++) {
    attachListener(elements[i], i);
}

Even with this option, sometimes programmers still use the immediate function because it conveys better their intended message to readers.

If your application uses the let idiom, wouldn’t it be nice to have new syntax for it?

for (var i=0, ilen=elements.length; i<ilen; i++) {
    var element = elements[i];
    let (num = i) {
        LIB_addEventListener(element, function(event) {
            alert('I was originally number ' + num);
        });
    };
}

With num and i together it is much easier to read this code and a new scope containing new has been introduced so the closure works properly. Once again, the addition of new syntax can tune the language better to your application’s needs.

Modules

One of the most common idioms in JavaScript programs we all know and love is usually called “the module pattern.” This idiom provides the benefits of encapsulated variables that are private to the module and imparts sanity to our code.

var event = (function() {

    // private variables
    var listeners = [];
   
    function addEventListener(f) {
        listeners.push(f);
    }

    function clearEventListeners() {
        listeners = [];
    }
    
    // ...
    
    // export the module's API
    return {
        addEventListener: addEventListener,
        clearEventListeners: clearEventListeners
        // ...
    };
}());

The goal of encapsulation here isn’t security. It is to ensure that other developers keep their dirty, monkey-patching hands off your module’s data.

The exporting can be done a few ways but no matter which way there is some boiler plate.

Importing is verbose also

(function() {

    // import desired properties of the event module
    var addEventListener = event.addEventListener;
    var clearEventListeners = event.clearEventListeners;
    
    // ...
}());

Some new syntax would be nice to convey the intent of the module pattern better.

module event {
    
    // private variables
    var listeners = [];
   
    export function addEventListener(f) {
        listeners.push(f);
    }

    export function clearEventListeners() {
        listeners = [];
    }
    
    // ...
}
(function() {

    import event;
    
    // ...
}());

The module pattern is almost everywhere and some new syntax to better express this idiom would better tune the language to all of our applications.

Inheritance

These idiom examples have been growing in how they each span an increasing number of lines of code. The JavaScript idiom that potentially spans the most lines of your program may be the inheritance idiom.

function Employee(first, last, position) {
    // call the superclass constructor
    Person.call(this, first, last);
    this.position = position;
};
// inherit from Person
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

// define an overridding toString() method
Employee.prototype.toString = function() {
    // call superclass's overridden toString() method
    return Person.prototype.toString.call(this) +
           ' is a ' + this.position;
};

What a mess. Yes JavaScript makes single inheritance like this possible by linking prototypes but it takes a lot of code to manually make super things happen they way you might like inheritance to work.

If there could be a maintenance nightmare that is it. The strings “Person” and “Employee” are sprawled throughout the code for the Employee “class”.

If classes with inheritance are a big part of your application, some syntax would really help clean up the code. Perhaps something like the following.

class Employee extends Person {
    constructor(first, last, position) {
        super(first, last);
        public position = position;
    }
 
    update(camera) {
        return super.update() + ' is a ' + position;
    }
}

That is a major improvement.

Learning from Idioms

These common idioms make it clear that JavaScript could use some new syntax for several reasons. The ability to do what we want is usually in JavaScript somewhere. The verbosity of the idioms is sometimes too much. We cut corners. Sometimes we avoid certain algorithms because the idioms are too verbose. The idioms are not self explanatory. They are inside secrets of the community and the intent is not easily recognized by outsiders.

The ECMAScript committee has recognized that the above idioms, and others idioms, are common across a wide variety of applications. There are proposals for all of these syntax cases in Harmony. Some of them may make it into the next version of ECMAScript and into the browsers for your use. If new syntax gets there eventually then you can use use it.

Idioms may have emerged in your application that do not appear in a wide variety of applications. For example, Node.js’s non-blocking I/O and heavy reliance on callbacks will undoubtedly result in idioms that do not appear in browser scripts. Syntax specific to just your applications will likely never make it into ECMAScript.

If you would like to use specialized syntax for the general idioms like those shown above or you would like syntax for your own idioms, what can you do?

If Only We Had Macros

Lisp languages have had full-blown macros for decades. Through macros, Lisp gives programmers the ability to tune the language’s syntax to best match their own applications. Because of its macros, Lisp has been described as “the programmable programming language.” Powerful stuff.

Lisp’s s-expression syntax, you know, the syntax with all those parens, gives the language a special property called homoiconicity. It roughly means the syntax of the language is also the syntax of its data structures or that a program’s parse tree uses the languages data structures. This homoiconicity makes Lisp’s macros possible.

JavaScript doesn’t have macros. A major reason for this is that adding macros to languages with C-like syntax, languages that are not homoiconic, is still a research topic. Excerpts from a short conversation on Twitter with littlecalculist, Dave Herman, Ph.D., ECMAScript committee member, and Mozilla Researcher:

@petermichaux
I believe @littlecalculist knows more about the research and possibilities for macros in ECMAScript. I’d like to know more also.
@littlecalculist
I have thoughts on it for sure. But macros for non-sexp languages is still very much a challenging research topic
@petermichaux
[...] We’ll turn blue waiting for macros.
@littlecalculist
Might I suggest you keep breathing? ;-) Seriously, I do hope to try, but trust me, macro system design is hard.

The message is pretty clear. JavaScript macros are not just around the corner.

Harmony Syntax ETA

Perhaps the syntax extensions in Harmony are all you dream of and more. If Harmony becomes ECMAScript 6 and ECMAScript 6 becomes ubiquitous then you’ll be all set. So all you need to do is wait...patiently.

First, let’s look at browser adoption. Unfortunately I’ll pick on Internet Explorer a bit, which has almost become a cliche, but not because I have something against the Internet Explorer development team at Microsoft or the newest versions of Internet Explorer. It is necessary to look at this browser because it is perhaps the most important case study for estimating when features will be available for all visitors to your web site.

As of May 2011, w3schools, which has relatively tech-savvy visitors, reports Internet Explorer 6 still has 2.4% market share. Net Market Share reports Internet Explorer 6 still has 10.36% market share. Your site probably has a market share somewhere between those two numbers but this browser is still hanging on even though it was superseded by Internet Explorer 7 in November 2006. How many people are still using Internet Explorer 6 or 7? The w3schools site shows 7.7% and Net Market Share shows 18.2%. These browsers just aren’t going away fast enough. A publicly available site (e.g. Amazon) cannot afford to ignore market share numbers this large.

There is no point in spending any energy moaning that users should upgrade their browsers or that “IE should die!” It won’t happen. I don’t know if it is true but someone once said to me “Internet Explorer users upgrade their browser when they upgrade their hardware.” For the past few years, hardware has certainly become sufficient that people don’t need to upgrade anything to use email, Facebook, Twitter, etc.

Suppose your web app is sufficiently advanced that you’ve decided that you only care about users with “modern” browsers. Google Apps recently announced that on August 1, 2011 they will stop supporting Internet Explorer 7. That is almost 5 years after Internet Explorer 7 was released.

Now think about this: Internet Explorer 10 is not out yet but, of course, even it won’t have Harmony’s syntax extensions. Let’s estimate that Harmony is approved as ECMAScript 6 in mid-2012 and Internet Explorer 11 is released in early 2013 with support for all of Harmony’s syntax. Five years after that, in 2018, the Google Apps team can drop support for Internet Explorer 11 and finally use Harmony syntax freely. (On August 1, 2011, they are also dropping support for the four-year-old Safari 3 and two-year-old Firefox 3.5 so the waits are still long-ish for other browsers too.)

Amazon developers might need to wait an additional 5 years before they can use Harmony syntax. That’s 2023!

Will you be satisfied waiting 7-12 years before you can start using syntax that would be helpful developing your web apps today? Being more optimistic, even if the wait is just 5 years, will you wait?

JavaScript is Dead.

Cause of death: semicolon cancer.

Perhaps due to JavaScript’s syntax alone, JavaScript does not have macros now and won’t have them soon if ever. Millions of programmers use JavaScript now and plenty of them are tired or tiring of the verbose idioms confronting them daily. They want new syntax now and won’t wait. For this growing group of developers, JavaScript the source code language is dead.

You had a good reign, JavaScript. We had some good times and wrote some cool apps together. May you rest in peace.

Long Live JavaScript!

Programmers like to control their own destiny and they are taking action. You can have all the new syntax you want for your browser scripts, right now, if you write in another source language and compile to the ECMAScript 3 dialect of JavaScript for the billions of browsers in the wild. By compiling to ECMAScript 3 you are completely freed from JavaScript’s syntactic evolution. As an added bonus, you can even fix some of JavaScript’s semantic gotchas with a sufficiently sophisticated compiler. JavaScript’s new life is as a compilation target.

Languages that Compile to JavaScript

There have been compilers to JavaScript for years now. In 2007, I started collecting a list of languages with compilers to JavaScript. There were JavaScript extension languages: the now-defunct ECMAScript 4, Narrative JavaScript, and Objective-J. There were pre-existing languages: Scheme, Common Lisp, Smalltalk, Ruby, Python, Java, C#, Haskell, etc. There were even brand new languages HaXe, Milescript, Links, Flapjax that were designed to address web programming needs.

Of these compiler projects, Google’s GWT Java-to-JavaScript compiler has probably been the most successful but I don’t see programmers who first learned a language other than Java rushing to use Java as their source code language. In fact, none of these compiler projects have accrued a significant long-term user base. At least in the parts of the web that I frequent, with the exception of GWT, it is rare to read about programmers using these compilers for any real projects. There are several legitimate reasons not to use one of these compilers.

Imagine you build a big project using one of these compilers and part way through find a bug in the compiler. The one maintainer of the compiler may have lost interest or time. Do you want to maintain a compiler? Does anyone on your team have the skills to do that? That ulcer is going to get pretty big while you prepare to explain to the CEO that you now need to rewrite the UI in JavaScript.

Just the thought of debugging compiled code when a production bug is filed makes my stomach churn. Core dump. What line number in the source code matches the line number Firebug is reporting for the compiled code? HURRY! That bug needs to be fixed now!!!!

You’ve used Objective-J for a big project and now you need to hire a new good programmer. What are your chances of finding the right person? They are probably very low. Just finding an available JavaScript programmer is difficult enough. If you use one of these alternate languages, it is very likely you’ll need to train each new person you add to your team.

Even without these compiler projects being wildly successful, the list of languages that compile to JavaScript has continued to grow. There is no doubt that writing a to-JavaScript compiler is a very cool project. Please pay me to write one.

There is one notable new entry in the list of languages that compile to JavaScript that is actually causing a big stir and is possibly changing the game for good.

CoffeeScript

I can tell you right now, I don’t know why CoffeeScript has the magic combination of features to garner the attention it has when other projects have failed. Significant whitespace and arrow function syntax. My gut reaction is yuck. There is plenty of things to like: default parameter values, rest parameters, spread, destructuring, fixing the whole implied global mess, even classes if you’re into that kind of thing and more. Many of CoffeeScript’s features are part of Harmony and so may be in browsers sometime in the future but if you use CoffeeScript then you can have them now. There is nothing like instant gratification.

Programmers are bursting with affection for CoffeeScript.

@pyronicide
Being able to use default values for function arguments in #coffeescript makes me immensely happy.
@_jdpage
CoffeeScript is wonderful. Now I am spoiled and will complain whenever I have to write JavaScript instead.

At the TXJS 2011 conference, Douglas Crockford apparently shared that he thinks “CoffeeScript is clearly good stuff.”

There is one aspect of the CoffeeScript project that I really like and it is summed up by the following two quotations. The first comes from Trevor Burnham, author of CoffeeScript: Accelerated JavaScript Development.

@trevorburnham
[...] It’s not about turning JS into Ruby/Python; it’s about having a syntax better suited to JavaScript’s inner goodness.

The second is from The Little Book on CoffeeScript.

CoffeeScript neatly sidesteps these [JavaScript issues], by only exposing a curated selection of JavaScript features.

The attitude expressed in these quotations really is great and genius marketing too. It is not CoffeeScript verse JavaScript. It is CoffeeScript enhancing the JavaScript programming experience. Could some different syntax and a restricted subset of JavaScript’s features really be better than plain old JavaScript?

Douglas Crockford seems to think so. For years, his JSLint has been hurting our feelings and demanding that we use very specific whitespace and syntax and that we avoid dangerous JavaScript features. Source code that passes JSLint has access to a true subset of JavaScript: the subset that he calls “the good parts.” This dialect of JavaScript deserves a name. Maybe GoodScript? After all, you are only allowed to use JSLint for good and not for evil.

The ECMAScript committee also thinks this is a good idea. The "use strict" pragma introduced in ECMAScript 5 not only restricts some language features like with, strict mode even changes/fixes the semantics of some parts of the language. Because of the semantic changes, ECMAScript 5 strict is a different language or at least a different dialect than ECMAScript 5 non-strict.

CoffeeScript, GoodScript, and ECMAScript 5 strict share common goals of keeping you away from the dangerous parts of JavaScript while giving you access to the valuable, safe parts. Each enforces these goals differently but they are enforced one way or another. You don’t get new syntax with GoodScript. It is already JavaScript and ready for the browser. You don’t get to use ECMAScript 5 strict because it is not available in all browsers yet and won’t be for years.

So CoffeeScript seems to be targeting a particular need of web development and maybe that is something other to-JavaScript compilers haven’t done or haven’t done well before.

CoffeeScript is also a reasonably thin skin over JavaScript. One consequence of this is that the compiled JavaScript code is reasonably easy to read and not brutal to debug (so I’m told.) This reduced debugging fear is contributing to interest in CoffeeScript.

CoffeeScript almost feels like a set of macros for writing JavaScript programs.

Since CoffeeScript compilers are in the hands of developers rather than the visitors to sites, you control which version of CoffeeScript you are using. You can upgrade at will. This also means CoffeeScript does not need to be standardized and go through the subsequent painfully slow growth of a standardized language. CoffeeScript can grow at the rate of its community’s imagination and desire. JavaScript standardization was essential to the success of the web but the same constraints do not apply to CoffeeScript.

Well then I’m going to invent my own language.

You can do this and it would be a great exercise. You’ll be able to call yourself a compiler writer which is pretty darned prestigious.

The danger of inventing your own language lies in the thinking that you can do better than JavaScript has done in the long run. Language design is hard and I bet your language will grow its share of unsightly hairs. Maybe not as many hairs as JavaScript but still. CoffeeScript hasn’t hit puberty yet but there are already signs that hair follicles may exist.

@maxsamukha
CoffeeScript: The way variables in outer scopes can be accidentally overwritten is fishy. How bad is it in practice?

You were so proud that your simple, readable compiled code was easy to debug. That will become harder as you realize the compiled code’s semantics aren’t quite what they were supposed to be in corner cases.

Idioms will appear in your language and someone will fork your compiler to do away with those idioms (unless your language happens to have macros.)

Enough with this nay saying. Go and write your own language right now. You’ll be a better programmer for it.

What’s missing from JavaScript the target language?

JavaScript is embarking on a new life as a compilation target. It is a capable target for many language features but it could use improvement. In his JSConf.US talk, Brendan Eich stated that one the goals for Harmony is to be a better target for to-JavaScript compilers.

Compiled JavaScript can run slower than hand-written JavaScript just like compiled C can be slower than hand-written Assembly (though not always.) Some inefficiency in compiled JavaScript is tolerable because JavaScript virtual machines are fast and the DOM is the bottleneck anyway. That said, some potential source code languages have semantics sufficiently far from JavaScript’s semantics that the compiled code is so inefficient that it cannot realistically be used in production web apps. There are already features in Harmony that will enable some of these languages to be compiled to efficient code and thus make these viable source code languages.

Proper Tail Calls

Programs in Lisp languages depend heavily on recursive calls to properly tail recursive procedures. The proper tail calls proposal in Harmony will allow these programs to be compiled to JavaScript without the inefficient trampoline technique currently necessary to avoid overflowing the call stack. Awesome! Let’s look at that in a bit more detail.

The following JavaScript is an example of mutually recursive functions which would work fine in Lisp but since JavaScript currently does not have proper tail calls, will overflow the JavaScript call stack when number is large.

function isEven(number) {
    if (number === 0) {
        return true;
    }
    else {
        return isOdd(number - 1);
    }
}

function isOdd(number) {
    if (number === 0) {
        return false;
    }
    else {
        return isEven(number - 1);
    }
}

isEven(100000); // InternalError: too much recursion

In the above code, a call to isEven(100000) isn’t complete and removed from the call stack until isOdd(99999) returns which isn’t complete and removed from the call stack until isEven(99998) returns and so on. That’s a lot of calls on the call stack! And there is no need for them all to be on the call stack. isEven(100000) doesn’t have anything intelligent remaining to do once it calls isOdd(99999) because the call to isOdd(99999) is the very last thing in isEven(100000). The call is said to be in tail position. isEven(100000) is just waiting to return the value returned by isOdd(99999) and a clever language can just pop isEven(100000) off the call stack and replace it with the call to isOdd(99999) thus saving space on the call stack.

With trampolines we can ensure that even in JavaScript the call stack doesn’t grow large. The following is just a sketch of how trampolines might be implemented and how isEven and isOdd might be compiled for a JavaScript interpreter that doesn’t have proper tail calls.

function bounce(ret) {
    while (typeof ret === 'function') {
        ret = ret();
    }
    return ret;
}

function isEven(number) {
    if (number === 0) {
        return true;
    }
    else {
        return function() {
            return isOdd(number - 1);
        };
    }
}

function isOdd(number) {
    if (number === 0) {
        return false;
    }
    else {
        return function() {
            return isEven(number - 1);
        };
    }
}

bounce(function() {return isEven(100000);}); // true

You can see the extra overhead of the bounce function which implements the trampoline calls is quite onerous. It creates closures for each continuation, doubles the number of calls, and must examine the returned value after each bounce; however, isEven(10000) does complete and is removed from the callstack before isOdd(99999) is called. The full computation completes in constant call stack space.

The bottom line is trampolines incur too much overhead. They incur so much overhead that when Rich Hickey created Clojure, his Lisp for the JVM, he decided his language could not have proper tail calls because trampolines were too expensive. That must have been a painful decision for someone who loves the Lisp family of languages.

The good news is that the ECMAScript committee has recognized this deficiency in JavaScript and has added proper tail calls to Harmony. This will benefit programmers writing directly in JavaScript and developers of to-JavaScript compilers.

Lambdas

Another strawman proposal not yet promoted to Harmony is the Block Lambda Revival which combines some new syntax with a new language construct called a lambda. A lambda is a callable thing, like a function, but it obeys Tennent’s Correspondence Principle. Tennent’s Correspondence Principle states that wrapping an expression or block of code in an immediate lambda should not change the meaning of that wrapped code. JavaScript functions are not lambdas and do not obey Tennent’s Correspondence Principle. For example,

function one() {
    return 1;
}

one(); // 1

is not the same when the return line is wrapped in an immediate function

function one() {
    (function() {
        return 1;
    }());
}

one(); // undefined

The syntax of the block lambda proposal for a lambda that takes two arguments and sums them is {|a, b| a + b}

Using the syntax of the block lambda proposal we can wrap the return line in an immediate lambda without changing the meaning.

function one() {
    ({||
        return 1;
    }());
}

one(); // 1

Thanks to lambdas obeying Tennent’s Correspondence Principle, the return still means return from the function one.

You may ask “Who cares about this computer science-y stuff?” to which I reply “Did any of that macro business seem useful?” because lambdas are a fundamental building block in the code generated by many macros. And since lambdas play nicely with JavaScript’s return, arguments, and this, lambdas would be a valuable addition to the language for compiler writers.

I’m focusing on the JavaScript-as-a-target aspect of the block lambda proposal. If you plan on writing in JavaScript forever after, the proposal has other benefits for you too that don’t matter to compiler writers.

The block lambda strawman has not yet been promoted to Harmony and so currently doesn’t have a path into ECMAScript 6 and browsers around the world. The standardization process is slow. Maybe there will be another decade stall in evolving the language like there was after ECMAScript 3. Maybe the next edition of ECMAScript will be the last edition. Better to get the best stuff in there than hope to get it in later. If you care about the future of JavaScript and think lambdas would be a benefit to the language then let the ECMAScript committee know by sending a message to the es-discuss mailing list in support of the block lambda proposal. Powerful, orthogonal language features like tail calls and lambdas which have no efficient workarounds may be the most important additions in the next edition of ECMAScript.

What’s missing from the browser?

The browser can help JavaScript succeed in its new life as a compilation target. The browser interprets compiled JavaScript and complains when the compiled code has an error. The error messages contain line numbers in the compiled code but you want to know the line number in source code.

The Mozilla crowd has an open ticket and a dev tools project to ease debugging source code by mapping compiled code lines to source code lines. Since you control the browser in which you primarily develop and test, you can use this feature as soon as it is ready.

Somewhere I read that the Webkit folks are developing similar source code debugging assistance but I cannot find any concrete evidence.

Polyglot

JavaScript’s monopoly in the browser has meant front-end programmers all speak the same language. This has given the community a lingua franca enabling good communication and code sharing. We are now headed for a polyglot future where you choose the language(s) you want to learn and use for developing browser applications. Maybe you are only using a few JavaScript language extensions via Traceur and compiling templates to JavaScript with Mustache. This still means that the CoffeeScript programmer won’t understand your source code immediately.

This divergence was inevitable as it has happened on all previously successful platforms. There have been multiple languages for building native applications almost forever. C is still common but C++, Objective-C, and many other languages are available. The JVM was intended to run programs written in Java but clever developers have added other languages like Clojure and JRuby as options. Microsoft recognized what seems to be a human psychological need for a variety of languages and developed its .NET CLR platform for multiple languages from the beginning. Programs written in Basic, C#, IronPython, etc can all be run on the CLR.

Barriors to communication in the front-end community are not new anyway. A developer using Dojo cannot immediately understand the source code of an application written with jQuery or YUI. There is a plethora of libraries, some very different, that add the ideas of class-based inheritance to JavaScript. So we already have our barriors even within JavaScript.

Having multiple source languages will increase the barriers in our community. Programmers will still need to know JavaScript, at least for a while, but in a few years they may know other source languages better then they know JavaScript.

Choice is a blessing and a curse.

Summary

It is great having the opportunity to watch JavaScript’s transition to a new life as it happens. It’s impossible to say which languages will end up winning market share in the to-JavaScript compilation but it is sure to be interesting. CoffeeScript is gaining momentum now but I think many other successful source code languages will follow.

What do you think will happen?

Comments

Have something to write? Comment on this article.

Marek Stasikowski June 25, 2011

I would be a really happy panda if things speeded up a little bit with introducing and _correctly_ implementing standards of the new versions of JS.

But still, seeing so many widely used, little to huge, easy-to-learn to advanced abstractions built on top of JS itself, I don't see eg. CoffeeScript taking over.

Something like CoffeeScript already happened to CSS - Sass and Compass. That is, CSS done right, which compiles to standard CSS. And it's been around for a long time... yet it isn't like overly popular, despite having a plethora of time saving, repetition eliminating aids to the developer, with Sencha Touch being probably the first major project to take advantage of it.

I'd rather see such supersets/subsets/mutations of JS in the role Flash has in relation to what browser engines can do - leading the pack, showing how things can be done better, but never actually becoming the pack itself.

roger June 26, 2011

javascript is the basic of our decade.

Joscha Bach June 26, 2011

I am looking forward to Harmony with great anticipation, and I agree on CoffeeScript's niftyness. But I dislike the compilation approach, for instance because it perverts debugging.

Meanwhile: have you looked at Mootools? Its a minimalist JS library that gives you many useful idioms and addresses most of the issues you mentioned, especially class inheritance and default options. Mootools allowed us to produce much cleaner, more maintainable code, but in native JS.

Steve June 26, 2011

All those nifty improvements and not a mention of types. I simply do not understand why people do not want type information. It helps the compiler, it helps the IDE, and it helps the programmer. Probably the biggest problem I have when dealing with javascript is looking at a function which takes some arguments and not knowing anything at all about what those arguments are.

I'm glad to see you mentioned Haxe, which I believe is a much better programming language than Javascript or Coffeescript. But, it's also aimed at different ends. I want a real programming language. Something in which I can describe data structures, types, methods, classes, all the real guts of a system. I guess Coffeescript is good for what it's aimed at: being a better scripting language.

Peter Michaux June 26, 2011

Steve,

You might be interested in the guards strawman. It's not everything you want but it might be enough.

Luciano Ramalho June 26, 2011

Take a look at the Boo language. It implements macros, and does not use s-expression syntax.

Esa-Matti Suuronen June 26, 2011

Here's a ticket for Webkit Web inspector support for compile to JavaScript -languages:
https://bugs.webkit.org/show_bug.cgi?id=30933

Peter Michaux June 26, 2011

Esa-Matti,

Thanks for the link.

Trevor Burnham June 26, 2011

Thanks for mentioning my book.

I think the big question you should be asking is: "If/when are we going to see JavaScript really become 'the new bytecode'?"

People ask me this a lot. When I talk to Rubyists about CoffeeScript, their first reaction is often, "Wait, why create a new language? Why not just compile Ruby to JavaScript?" And the two answers I give are:

  1. You'd lose compatibility with jQuery and other JS libs, and would have to start from scratch with a Ruby wrapper around the DOM.
  2. The performance overhead would be huge, especially if you preserved things like "every number is a BigDecimal" and "strings are mutable."

But as JS performance continues to improve, #2 might not be such an issue. In 5-10 years, maybe JavaScript really will be like the JVM, with an abundance of different languages running on it. Until then, I suspect that milder, more predictable precompilers like Kaffeine and CoffeeScript will predominate, since they make it fairly easy to produce optimal JS. It'll be a while yet before people are willing to lose control of the resulting JS entirely.

Jacques June 26, 2011

Believe it or not, this article gave me a very good refresh on my CS classes.

Finding good articles that teach you things in a simple, yet deep and accurate way is very rare.

Thanks a lot for that.

Rasmus Schultz June 26, 2011

Wow!

Thank You, Peter - this article was sorely needed. I hope this puts a damper on the extreme JS over-hype happening everywhere lately.

Very clear, very detailed and very informed article. I didn't need it myself, but I read through it myself, and I believe a lot of people out there need this article badly - to help them adjust their binoculars and see JS for what it really is.

Without a doubt, JS is one of the most important languages, and will continue to be so for years to come - but it really is poorly suited as "bytecode" language, as-is. It quite frankly wouldn't take much to fix that, but getting all the JS vendors to standardize on such a feature could take years of hard work...

Again, excellent article! thanks!

Greg A. Woods June 26, 2011

Interesting article! I'm still not sure what to think of JavaScript.

(remember when one of the main ideas for browser "plugins" was so that you could add your own scripting language to the browser?)

This all reminds me to take another look at the Lively kernel..... I first encountered it after doing some refresher reading on Self after having attended a talk by Adam Spitz and learning about the Klein VM, which left me wondering what David Ungar was up to lately, and it all inevitably lead me back to Smalltalk and then wondering what Dan Ingalls was up to now too.

http://www.lively-kernel.org

Joss Crowcroft June 26, 2011

Great article! Really struck home for me, made me wonder why I've been trying to hold off on exploring coffeescript.. I assume it was fear of unlearning bad JS habits.

Ps. You might be being a little generous to w3schools here: "... w3schools, which has relatively tech-savvy visitors..."

Martijn June 27, 2011

> class Employee extends Person

You're making a grave mistake here. Javascript does not support classes, and it *shouldn't*. Classes would flush it's dynamic nature down the toilet, and this dynamic nature is what makes javascript as powerful as it is.

You're certainly not gonna mix classes with prototypes, since they are each other's opposites. Many porgrammers prefer classes, but that's only because they're used to it, not because they're better.

Javascript does lack some constructs found in classical inheritance that can be useful in prototypal inheritance (such as properties), but this can be solved much more subtly.

Peter Michaux June 27, 2011

Martijn,

The class proposal in Harmony is only syntactic sugar. It doesn't change how the prototypal system in JavaScript works or add any new language constructs.

Daganev June 27, 2011

You know, reading this article I couldn't help but have the same though go through my head multiple times.

Why doesn't Adobe work with other companies to make ActionScript part of the browser?

Patrick Mueller June 27, 2011

My biggest gripes w/JavaScript, in the browser, are lack of first class support for modules, and ease-of-use stuff for classical OO structuring.

For the first, I've been using my library for CommonJS for the browser - https://github.com/pmuellr/modjewel. There appear to be many CommonJS and CommonJS-like environments available for the browser; folks can probably find >something< they're willing to live with, if they want modules.

For the second, I've been using a preprocessor approach - .scoop compiled with this - https://github.com/pmuellr/scooj. This has worked out well for me.

Both of the compilation bits for these tools maintain the same line numbers in the compiled versions as the original source versions. I was worried that I'd be losing too much information in the debugger without this property.

I'm currently using both of these for http://phonegap.github.com/weinre/, but have had a bit of push-back on the .scoop files. I started the scoop work before CoffeeScript, and have been watching CS on the sidelines for a while now. CoffeeScript is certainly an easier sell than .scoop files at this point, so I'm currently working on a .scoop -> .coffee file translator :-) Not sure how the debugging is going to work out, without special help from the debugger, but think it will be survivable. Would of course be nice to have special source-mapping support in tools like FireBug / Web Inspector. Not sure if that's enough either - do we need special frame / local variable handling as well? Hoping not, for CoffeeScript anyway.

For WebKit's Web Inspector, some of the work currently available to handle de-obfuscating files can likely be used for other source-mapping needs; for instance, the file DebuggerPresentationModel.js contains some interesting looking goop.

Fatih June 27, 2011

I do not believe JavaScript is dead. You have some good points but still it is alive

Todd June 27, 2011

I'm going to get beat up here but...why compile to JavaScript? Shouldn't there be a cross-browser VM that allows true compilation first? I'm no JavaScript pro but 'compiling' to an interpreted, text format doesn't allow for optimizations provided by the JVM, CLR and yes...Flash.

I said it. Most JavaScript lovers hate Flash, but the truth of this is, it runs more consistently across browsers and performs WAY better than JavaScript because it is running on a VM. ActionScript3 is a much richer language than JavaScript. And after trying out several JavaScript based UI frameworks, I'm still convinced the Flex framework is better. It scares JavaScript ninjas because Adobe 'owns' it and allows nubes to build UIs that are richer and faster than uber skilled, smart JavaScript developers wasting their time with 'if(ie8) { ... }'.

Regardless your hate for Flash. That's religious and should be kept away from open minded technical discussion. Who cares about he 'next' web language? What is the next VM that allows powerful languages without all of JavaScript's baggage prosper.

Having JavaScript only in the browser is NOT good for web development. Having Java only on the server is bad now. But with a powerful, VM, we are no longer constrained by this. Building other languages on top of JavaScript is like building other JVM languages on top of the JVM from 1.0. You are building your castle in the sand.

Get a good foundation that is built into ALL browsers. I'm not even sure HTML5 will be that. But I've already said too much.

Peter June 27, 2011

Missing default parameter values? I don't want to have them at all. I want a language that required all parameters to be specified, so that if you add a parameter to a method definition, you are forced to check each call for its validity. Adding a parameter and giving a default value is a sign of laziness. You just assume it's ok for every call, but in a program of substantial size, you simply don't know.

Some of the other things you suggest do make sense, but to me the greatest needs for JS are:

  1. Data types and Type safety
  2. Real classes
  3. Compilation in stead of interpretation

I.O.W. turn JS into a real programming language in stead of a scripting language that has run out of hand. Currently, JS is a building that is too large for its foundation.

I don't dig the idea of compiling into JavaScript. It's nothing more than a workaround for the fact that browsers don't have a better way to execute client side code. The effort put into this kind of compilers should have been put in creating a better and compiled, language for client side code execution in browsers.

Greg A. Woods June 27, 2011

My hint about plugins was somewhat intended to suggest that a more general-purpose VM in the browser would be better than using JavaScript as the intermediate language.

Note that Chrome's V8 _is_ a virtual machine, BTW. Dunno yet if it could be used in such a way as to support alternate languages though. Personally I'd love to have Self, Smalltalk, and/or Scheme, and/or maybe Lua in there.

All of this said, I still, and will probably always, despise the idea of allowing any kind of third-party code execution in the browser, especially if it can do anything more than take keyboard and mouse input and fiddle with pixels and fill in forms (and even that can lead to trouble). Flash is evil not (just) because of any technical (mis)feature, but rather because it is both closed source itself, and it's allowing third party code to do potentially evil things.

Originally I thought plugins might be usable as ways to get authorized third-party code into the browser, but of course that's a portability nightmare and not viable in the real world unless it's done in much the way that Flash and JavaScript are done, so that doesn't help any either; unless maybe you force the VM to only ever load signed and authorised code from the local filesystem and never ever directly from the network.

arbbot June 28, 2011

I can't avoid to feel that all the points you make are just the things that languages that C# already has. I work with JavaScript, PHP and Flex developers all the time, and I've seen a lot of their code. It seems to me that all languages try to come close to what C# already has and has had for several years now. I recommend to take a look at its syntax and the different tech flavours for different solutions and platforms.

Sandro Pasquali July 1, 2011

I don't think you've made the case against the viability of Javascript as a popular and widely used language. There may in fact be such a case to be made. This article has failed to argue convincingly for that conclusion due to the several clear logical fallacies it contains.

I think you want to assert that there is a large population of developers who are "tired or tiring of the verbose idioms confronting them daily" while working with Javascript, that this frustration can only grow, that this frustration will grow too quickly for it to be remedied by Harmony (or some other white knight), and therefore some drastic action must be taken to save the language. The proposed solution is some sort of ideal 3rd language that compiles to Javascript, and this means that the future of Javascript is as a compiler target.

I offer these thoughts in order to encourage you to continue your research, and to continue your valuable contributions to the growing body of research around Javascript and its usage.

I'd just be argumentative if I claimed that your premises are false (that your examples demonstrate bad examples rather than bad JS features), mentioned "appeal to novelty", or quoted Voltaire: "The perfect is the enemy of the good". I do want to say that I in no way want to imply in what follows that I agree with the claim that JS's syntax is "bad" to any significant degree.

Bald assertion fallacy. No evidence has been presented that there is in fact a majority of developers who are "tired or tiring..." &c. Indeed, even if there were such evidence, appealing to the masses is itself a fallacious way to argue. This logic can just as easily be used to counter your own argument: "Because Javascript is the most widely used language in the world it is therefore [The best designed? Better than Ruby? Than Lisp?]".

False dilemma. Can you agree that the viability of a language is not wholly determined by its syntax? What about speed? What about documentation, or knowledgeable workforce? Investment? Existing process? What about contextual constraints? Is Objective-C also dead, due to its verbosity? (is it verbose? by what measure? Machine code is very terse. Should we all be using that?) "Either ideal syntax, or full abandonment" lacks some finesse, doesn't it? It sounds...ridiculous, no?

Hasty generalization. If it is true that there are some unnecessarily difficult/verbose/tedious syntactic constructs in JS, does this mean that the entire language is difficult/verbose/tedious?

Fallacy of the undistributed middle:

All doomed languages have a difficult syntax
JS has a difficult syntax
Therefore JS is a doomed language

Or:

All birds have feathers
Hats have feathers
Therefore all hats are birds

I'll end there not for lack of material but for lack of further necessity.

Mariusz Nowak July 2, 2011

Peter,

Awesome insight!

What might be the issue, is that JavaScript attracts programmers from different worlds. We have functional (SICP, Lisp background) and OOP (strong types, classes, C++, Java) both of which want to make this language more familiar to them. JavaScript is kind of torn apart, but still much closer to functional approach (which I personally favor).

Maybe it'll be good to write good introduction to Lambdas aimed at JavaScript, with some real world examples, written plain way, showing how it can be practically useful. I just assume that there's large and important group which just don't get lambdas/macros concept.

Robert Green July 25, 2011

It seems to me that there are two ways forward - either change javascript into what you want, or start again. What type of analysis is available to inform the choice?

Should any one language try to be all things to all people?

Basic used to be everywhere, it was very simple and anyone could program in it. Microsoft slowly turned it into the massive, complex language it is now, it is only popular because it’s a Microsoft language.

Javascript was increadibly popular mostly because it was so simple to program in. Even badly written scripts “worked”, just like Basic programs used to. Will turning javascript into a fully featured, high-end programming language remove the beauty of its simplicity?

The result of making javascript perfect could sew the seeds for its destruction.

Have something to write? Comment on this article.