Scaling JS++: Abstraction, Performance, and Readability

Sometimes, people will argue that C++ scales better than C for development teams and large projects because it has classes. While code organization is certainly helpful, Linus Torvalds will argue it is unnecessary because there are other ways of achieving code organization – such as prefixing function names with a “namespace.” JS++ is influenced a lot by C++ and Bjarne Stroustrup’s philosophies. While most people point to classes as the reason for C++’s success and scalability, there is a more subtle reason it scales so well: readability.

The C++ STL provides a level of abstraction without sacrificing performance. Stroustrup said he wanted std::vector to be as fast as C arrays. You can implement these details yourself, but why not just use std::vector?

While working on the JS++ Standard Library, Stroustrup’s philosophies have once again come into play.

As an example, think about converting a JavaScript number from decimal (base 10) to hexadecimal (base 16). Can you think – off the top of your head – how it would be done? There is a certain pleasure derived when you can read through someone else’s code as clearly and effortlessly as you might be able to read a book. We enforce these standards internally at Onux, and I’m going to reveal how it influences the design of JS++.

Getting back to the example, this is how it’s done in JavaScript:

var x = 97;
x.toString(16);

I’ve argued that we need to deprecate JavaScript’s Number.prototype.toString(base). Instead, we are proposing a toBase(unsigned int base) method to convert from base 10 (decimal) to a specified arbitrary base. Consider the readability of the following functions:

x.toString(16);
x.toBase(16);

Both functions do the same thing, but I’ve argued that no programmer will ever have to look up what toBase(16) means versus toString(16). The beauty of a compiled language is that we have full control over optimization. Of course, in JavaScript, you can do this:

function toBase(number, base) {
    return number.toString(base);
}

All else being equal, and you care about performance, wouldn’t you much rather have this?

x.toString(base);

In JS++, we can perform this exact optimization in a process known as “function inlining”. Here’s an example from Wikipedia. In other words, even though JS++’s toBase(16) is clearer than toString(16), there is no loss of performance because toBase just gets compiled to toString with no additional function calls; the toBase method basically doesn’t even exist in the final generated code.

We can take this one step further. Converting from base 10 (decimal) to base 16 (hexadecimal) is quite common. Why not provide a Standard Library function to do this?

char x = `a`;
x.toHex();

In this case, toHex() is just an alias for toBase(16), which is in turn an alias for toString(16). With each layer of abstraction, we gain more clarity and readability in our code. This makes it easy for others to work on our code, it makes it easy to scale development for teams, and – most of all – each layer of abstraction results in no performance loss. In fact, toHex() just gets compiled to toString(16).

Think for a moment. You’re tired, groggy, and unmotivated. Would you rather read code that looks like toString(16) or toHex()? This readability gain has only been focused on 1-3 lines of code so far. What we want to achieve with JS++ will expand across your entire code base.

When I meet programmers and they say they have problems with “spaghetti code”, I almost always guess (correctly) that they’re working at a JavaScript house. Classes – by themselves – won’t stop developers from writing unreadable code. We need abstraction… without sacrificing performance. This is what’s coming with the JS++ Standard Library. Here’s to a better future!

Roger PoonRoger Poon
JS++ Designer and Project Lead. Follow me on Twitter or GitHub.