The case for JS++

JavaScript has exploded. It’s everywhere: the browser, the server, your phone, IoT devices, and more. However, JavaScript can be brittle. The language was notoriously designed and developed in just 10 days, and its creator, Brendan Eich, has become JavaScript’s most prominent apologizer.

JavaScript is controversial. Rarely have we seen a language divide software developers so much. I shared the stage with Geoff Schmidt, CEO of Meteor, in San Francisco in February. He asked the audience to raise their hands if they love JavaScript; surprisingly, moments later, he asked the audience to raise their hands if they hate JavaScript. It was a JavaScript conference, and I was surprised to see hands go up.

However, this illustrates the reality that besieges us: a rare moment that succinctly captures the zeitgeist of our times. There are developers who feel forced to use JavaScript. It’s the only option in browsers. “Monopoly” is a strong word in technology, but it wouldn’t be a stretch to concede that JavaScript monopolized the web platform. If the voices echoing in the corners are any indication, JavaScript did not achieve this monopoly through merit.

Yet JavaScript isn’t without merit either. Scheme wrapped in a C syntax was serendipitously clever. Nevertheless, a line needs to be drawn between being clever and being pragmatic. There’s a reason Scheme (and JavaScript) are not among the first-, second-, or even third-choice languages in modern complex software systems in organizations where engineering principles are valued.

If you didn’t like JavaScript, it was because you didn’t “understand” JavaScript. Voices and opinions were dismissed by the JavaScript community: You didn’t “understand” prototypical inheritance, and you didn’t take the time to learn JavaScript “properly.” Developers were saddled with blame; it wasn’t because the language was lacking, it was because you weren’t good enough. Speaking as a developer that understands JavaScript deeply enough to develop a robust type system on top of it, I know it’s possible to understand JavaScript well… and still be unsatisfied with it.

As a result of being ignored and demoted to second-class citizens, the “other” developers (often having to use JavaScript out of necessity) have had their problems unaddressed. Fortunately, these problems are being solved.

JS++JS++ is a web programming language built for software engineering. It is built with engineering principles: strong, solid foundations via a type system that can leverage the full JavaScript ecosystem while guaranteeing your types will be correct at both compile and runtime. It’s a programming language designed over multiple years, not 10 days.

JS++ incorporates object-oriented programming (OOP) with classes, despite how much JavaScript developers riot against this, and enforces a rigid structure that guarantees maximum compile-time analysis so the compiler can detect errors early before you ship into production.

JS++ is a superset of JavaScript. (In fact, it was the first superset of JavaScript when it initially went into alpha in October 2011.) What this means is that all valid JavaScript programs are valid JS++ programs. JS++ is designed with three key uses in mind:

JS++ compiles to JavaScript and can run anywhere JavaScript is supported: in the browser, on the server, on mobile devices, and so on.

There are other JavaScript supersets available, but JS++ is different through its core engineering values. Engineering fundamentals are the same across industries and disciplines. Whether you are building a program, bridge or skyscraper, it’s fundamentally the same: build on a strong foundation and enforce a rigid structure.

In a similar spirit, one of the key innovations behind JS++ is “type guarantees.” Whereas we’ve previously had to content ourselves with type checking, as engineers, we want guarantees: a guarantee the variables you declare as strings don’t become numbers, a guarantee the variables you declare as numbers don’t become objects, and a guarantee your class instances don’t become strings at runtime. This is what is known as type preservation, a byproduct of a “sound” type system.

Type guarantees: Beyond type checking“Well-typed programs cannot ‘go wrong,’ ” said Robert Milner. Programs have data, and data have types. Although it seems like JavaScript has no notion of “types” in its syntax, JavaScript programmers still need to be cognizant of types because curiosity inevitably leads to such operations as the subtraction of a string from another string. This has no real-world logical equivalent or explanation and results in errors. However, this is never enforced by JavaScript until it finally happens at runtime.

Type checking has grown in popularity for JavaScript in recent years precisely to counter these runtime type errors. Ideally, if we can run our source code through a linter or type checker, we should be able to identify and fix these errors before we ship our programs. However, the concern is that, at runtime, the types we declared in our source code are not reflected in the types for the actual data during program execution. This can be especially true when the generated code is JavaScript, which has very lax rules when it comes to data types.

To illustrate this point, let’s examine a basic variable declaration:

bool x = y;

This typically compiles to:

var x = y;

This is known as “type erasure.” In other words, the types were “erased” at runtime, and the compiled JavaScript has no knowledge of the types that were declared in the original source code. Popular projects that are known to perform type erasure are Microsoft TypeScript and Facebook Flow.

Erasing types introduces a tricky predicament. We have no assurances the variable “y” is indeed a Boolean at runtime. Remember: This is JavaScript. A variable that was once a Boolean can quickly become a string, number, object, or even the arcane “host object type.” Consequently, a vocal minority of developers remains unconvinced: If it’s still JavaScript in the end, we inevitably run into the same problems.

Fortunately, there are solutions. Slightly more sophisticated systems use “runtime contracts”:

assert(typeof y == “boolean”);

var x = y;

Runtime contracts can ensure types are correct at runtime. However, they have a glaring weakness: They take down the entire application on a single error. With runtime contracts, you risk having exponential points of failure. In software engineering, we want to reduce the potential points of failure.

We’ve worked on the JS++ type system since 2011. We explored every type system under the sun: Hindley-Milner type inference, gradual typing, soft typing, and more. The JS++ type system is optional and sound. In other words, you do not need to declare types for your variables and functions. Type annotations are completely optional. However, if you do decide to declare the type for a variable, it is guaranteed to be correct at both compile and runtime. This is the breakthrough in JS++, as previous systems could only achieve correctness at compile time or runtime, but never both.

JS++ achieves “soundness” in its type system by unifying all JavaScript types into a single type known as the “unified external type.” Type-checking JavaScript correctly and accurately is an incredibly complex problem, but JS++ solves the problem via simplification. Once the logic is simplified, JS++ “isolates” JavaScript. When data crosses from JS++ to JavaScript and vice versa, it needs to be safeguarded and converted. Therefore, JS++ is able to “preserve” types by preventing JavaScript from tampering.

In JS++, types are guaranteed. At compile time, the type system is “sound”—in other words, the JS++ compiler’s type checker can never be wrong because it’s not approximating. As an example, if the JS++ type checker determines at compile time that an expression will evaluate to Boolean, it will evaluate to Boolean at runtime. This is aided by runtime “enforcement.”

Runtime type enforcement is lightweight and straightforward. When we declare a Boolean, the compiler ensures the data always remains a Boolean via conversions:

var x = !!y; // Convert ‘y’ to Boolean via double !! operators

As illustrated in the example, JS++ will force runtime conversions to the type you declared. This example oversimplifies what JS++ is doing differently, but it demonstrates one of the key innovations for achieving “soundness” and type safety. It turns out JS++ isn’t just compiling to JavaScript; it’s compiling to typed JavaScript.

Conversions on primitive data types like Booleans and strings are implicit, automatic and straightforward. However, another challenge we faced in our design was how we could guarantee the types to be correct for constructed types. For instance, one “Employee” class within an organization may differ from the “Employee” class defined for another organization. In this case, JS++ enables developers to define custom conversion rules and logic.

Conversions are lightweight. They only need to be performed on variable assignments, function calls and function returns. If a conversion fails, you simply get the default value for the type, such as an empty string for the “string” data type. Furthermore, the compiler can optimize conversions so that they only occur at runtime when necessary. Thus, you get the benefits of type safety without sacrificing performance.

The example was oversimplified, and there’s a lot more science behind the JS++ type system, but this highlights one of the main innovations behind JS++: type guarantees. JS++ goes beyond type checking and guarantees the types you declare will be correct at both compile and runtime.

Object-oriented programming with classesJavaScript developers are philosophically opposed to classes. JavaScript’s most vocal defenders have long argued that JavaScript does support OOP via prototypes. Perhaps justified, they feel liberated from Java’s structure and rigidity. Yet, structure is one of the most fundamental aspects of engineering.

Structure is how we know an Employee class has a getName method. Structure is how we determine that getName was a typo that could crash the program by calling an undefined method. Structure is how the linker knows which modules were unused so we can perform dead code elimination.

Yet, the most painful verdict against JavaScript’s inheritance goes beyond structure. It’s not the computer science concept of prototypical inheritance versus class-based inheritance that we need to be arguing about. It’s the spaghetti code that is necessary to fully utilize prototypical inheritance in JavaScript due to its syntax. JavaScript was designed in 10 days, and it shows.

As developers tried to compensate for JavaScript’s shortcomings, the problems became exacerbated. Ad hoc inheritance, ad hoc module systems and so on began to appear. Bad came to worse. While JavaScript’s thought leaders were defending prototypical inheritance, the major libraries weren’t even using it. OOP in JavaScript became a melting pot of prototypes, objects, third-party retrofitted class systems, third-party module loaders, inconsistent namespacing patterns, and then some. It sounds like an enumeration of an engineer’s worst nightmares, except this is the reality we face.

If you can’t appreciate the years of work that went into JS++, you have to at least appreciate that we’ve managed to take all these diverse factors and universally simplify them to the point that JS++ is able to achieve “correctness” while enabling you to leverage any and every JavaScript library in existence.

For a superset of JavaScript, if structure is important in engineering, we want to know that the structure cannot be modified by accident. This is especially true on the web where it’s not uncommon to load resources from external web servers and, thus, introduce third-party and potentially untrusted code. This ventures into another concept of the JS++ type system: isolation. Essentially, JS++ “isolates” JavaScript, and we can imagine JS++ source code to be divided into “regions”: the JS++ region and the JavaScript region. Once isolated, JS++ is able to guarantee that the unsafe and untrusted JavaScript can never tamper with JS++ code and data.

Still, it needs to be understood that “classes” go beyond superficial syntax and runtime semantics. Object-oriented programming with classes brings with it knowledge capital and a wealth of experience. The talent pool expands to include experienced software architects and battle-hardened developers that can quickly add value to a project. Design patterns developed for classes no longer need to be clumsily adapted for prototypes. JavaScript developers still testing UIs with Selenium and headless Chrome will benefit from new and better techniques that have been known in structured languages for a while now. Software engineering is every bit a people problem as much as it is a technology problem, and class-based OOP brings some of the best people and brightest minds.

The end of the prototype debate is that real-world systems ranging from banking to rocketry are built with classes. Maybe prototypes enable greater “expressiveness.” Maybe prototypes enable greater “composability.” However, no amount of fear mongering can refute the fact that classes are working and working well. Lest my statements be taken out of context, JS++ was not designed for rocketry; however, if its underlying principles can be used to explore the cosmos, it can certainly be used to ship higher-quality web and mobile applications.

The little detailsJS++ was designed over many years. We think programmers will appreciate the finer details that show great care in the design and a deep understanding of the domain. For example, the popular syntax for declaring a typed variable in most JavaScript supersets looks like this:

var x : boolean = true;

There’s a little secret behind this: It’s much easier to parse a JavaScript superset with this syntax. Yet, this is a lot of extra typing. It’s frustrating. Programmers coming from a background in C++, Java or C# will appreciate the JS++ syntax:

bool x = true;

Additionally, the JS++ compiler is written in C++. As projects grow in complexity, we think developers will appreciate the extra engineering effort we invested in order to achieve the fastest compilation times. Compilation times are only one aspect of programming language performance. Runtime performance is arguably even more important, and we’re working on this too. Maximum speed is important.

The little details add up over time. JS++ wants you to have the smoothest development experience possible.

On patents
There has been some concern over my company, Onux, filing patents on the JS++ type system. The patent filings are a defensive mechanism. We don’t charge royalties for using JS++. We’ve sunk a lot of resources into R&D, and the result is the most reliable type system in the industry being provided to you for free. Lost in the chaos is that some of the most popular programming languages are patented. Microsoft’s C# is heavily fortified with patents but remains unencumbered.

I can’t speak for other programming languages, but, typically, when patents are used defensively to protect R&D investments, it’s used to stop competitors from copying rather than tormenting users. The JS++ compiler is free to download for a reason. Nevertheless, for the remaining skeptics, we think having type “guarantees” over type “checking” will interest early adopters and developers that value our same values and rock-solid reliability.

I’ve written extensively about the theory, problems and corner cases that need to be solved for static types to work with JavaScript. It takes a lot more than just adding “types” to JavaScript’s syntax. At least one of Microsoft, Facebook or Google would have figured that out by now if it were so simple! Yet, there’s a reason they have collectively failed to achieve “soundness” for so many years.

When you really begin to dig deep into the problem, you realize that the JS++ type system works in virtually every case. This takes experience, this takes time, and this takes effort. We’ve worked hard to come up with an innovative solution. When people ask us to lift our patents and make it open source, they are asking us to forfeit years of hard work to Microsoft et al.

It’s never too late for us to pivot on our patent stance because we understand it’s unpopular, but, presently, we are choosing to remain pragmatic even if it costs us die-hard anti-patent purists. JS++ was only just announced and is still in the developer preview stage, so a lot can change over time. However, Onux is not and will not be a freebie research arm for Microsoft, Google and Facebook. They have the resources and bright minds to find another way to achieve type guarantees.

For now, if you want type “guarantees” rather than just type “checking,” you use JS++. If you want to compile to “typed” JavaScript rather than just JavaScript, you use JS++.

Article Tags

About Roger Poon

Roger Poon is a founder, speaker, and developer and has been programming since 1997. He is founder and CEO of Onux, a programming language and compiler company, founded in London with operations in San Francisco and Silicon Valley. Roger is responsible for designing the JS++ programming language.