Design Patterns: The Template Method Pattern and Final Methods

C# got it wrong. Java got it right.

C# doesn’t let you “seal” methods that aren’t overridden. Java allows you to mark any method as “final” – whether it’s an overridden method or not. This subtle detail has interesting implications.

The Gang of Four’s “Design Patterns: Elements of Reusable Object-Oriented Software” was published in 1994—many years before C# was first released and just two years before Java was released. (Although, most of the code in the book was presented in C++.) The book presents the “Template Method” behavioral pattern. Template methods define the “framework” of an algorithm and leave subclasses to define the behavior. Unfortunately, if you cannot mark a template method as ‘final’ (or ‘sealed’ in C#), it enables subclasses to—potentially by accident—change the behavior of the template method.

Here’s a template method in action, written in JS++, to demonstrate how this might be undesirable:

abstract class Model
{
	abstract public bool validate();
	abstract protected void saveTemplate(IDatabase db);
	public final void save(IDatabase db) {
		if (!this.validate()) {
			throw new ValidationException();
		}

		this.saveTemplate(db);
	}
}

In the above class, the template method (“save”) is marked as ‘final’. Without ‘final’, an overriding method (or overwriting method, to use JS++ terminology) can potentially forget to perform business object validation before altering the database. This can lead to potential bugs and security threats.

Beginning with the next release of JS++, you will be able to mark any method as ‘final’.

Design Notes: Why isn’t System.Array.length an ‘unsigned int’?

It makes sense, doesn’t it? Array sizes should be unsigned because they can never be negative. Yet, JS++ chose to make System.Array<T>.length return a signed 32-bit integer (int). We’ve discussed this internally, and the underlying reasons are not so simple.

JavaScript

The most important reason is that this is a bug in JavaScript and ECMAScript 3’s original design. ECMAScript 3 15.4 specifies that Array#length is an unsigned 32-bit integer. However, it gets a bit tricky when you view these method signatures:

  • T[] Array#slice(int start) (ES3 15.4.4.10)
  • T[] Array#slice(int start, int end) (ES3 15.4.4.10)
  • T[] Array#splice(int startIndex) (ES3 15.4.4.12)
  • T[] splice(int startIndex, int deleteCount) (ES3 15.4.4.12)
  • T[] splice(int startIndex, int deleteCount, ...T replaceElements) (ES3 15.4.4.12)
  • int Array#indexOf(T element) (ES5 15.4.4.14)
  • int Array#indexOf(T element, int startingIndex) (ES5 15.4.4.14)
  • int Array#lastIndexOf(T element) (ES5 15.4.4.15)
  • int Array#lastIndexOf(T element, int endingIndex) (ES5 15.4.4.15)

All of the above deal with array indexes as signed 32-bit integers even though the specification clearly states array lengths are unsigned. Specifically, if we indexed arrays using unsigned int, we would break JavaScript’s indexOf and lastIndexOf (because they return -1 when the element is not found). This gets further complicated because Array#push and Array#unshift, which return Array#length, return unsigned 32-bit integers.

Just know that I brought the proposal forward internally for indexing arrays as unsigned int, but I shut down my own proposal after the self-realization that it would break indexOf and lastIndexOf — it was just unacceptable.

In other words, we were handicapped by JavaScript in our design (as we often are).

Java and C#

A lot of website backends are written in Java, C#, PHP, and – nowadays – JavaScript. JavaScript and PHP are dynamically-typed, so you don’t have to worry about signed/unsigned, but this brings me to Java and C#.

Java doesn’t have unsigned integer types. I actually feel like this can be a good design decision in some ways. It makes reverse array iteration intuitive and obvious: just flip the logic for forward random-access iteration around. Likewise, in C#, List<T>.Count returns a signed integer (32-bit). Just as in Java, reverse iteration with a for loop is just flipping the logic around.

With signed integers, you don’t have to worry about integer overflow. If you perform forward iteration with:

for (int i = 0; i < list.Count; ++i);

Then, intuitively, reverse iteration might look like:

for (int i = list.Count - 1; i >= 0; --i);

Of course, this won't work for C/C++ because, on the final iteration, you get integer overflow.

Once again, in dynamic languages like JavaScript, you don't even have to worry about such things. It was all abstracted away by dynamic typing.

Reverse Array Iteration

Reverse array iteration over unsigned types becomes non-trivial. Anyone that has done this in C/C++ will know what I mean. The correct way to do it is to do it in a way that takes integer overflow into account. In C and C++, array sizes are unsigned, and C doesn't have C++ reverse iterators. Here's the code in C:

int arr[3] = { 1, 2, 3 };
size_t len = sizeof(arr)/sizeof(arr[0]);

for (size_t i = len; i --> 0;) {
    printf("%d\n", arr[i]);
}

So you initialize to the length of the array (without subtracting 1) and i --> 0 is better formatted as (i--) > 0. Thus, inside the loop body, you will only access - at most - length - 1 and it will count down until zero.

However, this isn't intuitive unless you come from a C/C++ background, and most C/C++ programmers are not web developers.

Conclusion

Reverse iteration in for loops may or may not be intuitive for you I didn't want users tearing their hair out over a basic programming exercise of iterating over an array backwards. Coupled with the fact that ECMAScript 3's original design was buggy, it only made sense to use int instead of unsigned int to avoid breaking old code from JavaScript.

Oh, and int is just so much more pleasant to type than unsigned int with casts everywhere.

Metaprogramming: Programmable DCE (Dead Code Elimination) in JS++

Problem:

You’re writing a library in JS++. You need it to support as many web browsers as possible.

Some of your users’ visitors are on latest Chrome and support the latest HTML5 features. Some of your users’ visitors are from developing nations with limited mobile devices. Some of your users’ visitors are corporate users with legacy web browsers running intranet applications, and, if it isn’t broken, they won’t “fix” it.

In other words, you need to support as many web browsers as possible. However, adding polyfills for all browsers will slow down the library for all users: more code to deliver over the network, more parsing and initialization time on mobile, more code to execute at runtime, and so on.

Solution:

Programmable Dead Code Elimination (DCE).

In the same way that template metaprogramming was “accidentally” discovered in C++, programmable DCE was a technique that we never originally intended but stumbled upon. I’m filing under advanced JS/JS++ tips & tricks. You should know how to use bitmasks, getters, classes, and JS++ types (because JS++ is not a linter like TypeScript).


What is Dead Code Elimination (DCE)?

Dead code elimination (DCE) means that if you don’t use a module, class, or function, it will not be compiled into your final output.

Here’s a simple example:

void A() {}
void B() {}

A();

In the above example, only the function A gets called. The function B never gets called and never gets executed. Therefore, it is safe for the compiler to not include B in the final compiled output.

A real-world example of the need for dead code elimination in JavaScript (but not JS++) is jQuery. You have to include the entire jQuery library even if you only use one function.

Live Example: JS++ Sockets (Real-time Streaming)

The JS++ Sockets library provides low-overhead real-time streaming even for legacy web browsers. It’s “low overhead” because we avoid long polling in almost every case except for the very first Android phones (HTC Dream and the like). Therefore, you get real-time streaming without the HTTP header overhead from constant polling, and you don’t have to deal with the delays of polling. (This can be useful for multiplayer games, corporate finance applications on legacy browsers where excessive latency is undesirable, or just to save a pretty penny on your bandwidth bill.)

JS++ has had support for dead code elimination since October 2016 (version 0.4.2). However, it wasn’t until we worked on JS++ Sockets that we encountered the need for “programmable” dead code elimination. In addition, JS++ users have been asking us to stop shipping polyfills for old browsers they don’t need because all their customers are on modern browsers.

JS++ Sockets can be instantiated like so:

new Socket(
    "127.0.0.1",
    8081,
    Socket.WEBSOCKETS | Socket.IE6 | Socket.IE7
);

It’s in the bitmask where all the magic happens. If your customers don’t use IE6, don’t include the Socket.IE6 option. If your customers use ONLY IE7 (like some big companies supporting legacy code), you can specify only the IE7 option. This gives the users of your library the flexibility; they’re not shipping thousands of lines of code they don’t need.

What’s interesting is that the options in the bitmask are actually getter functions. It only looks like an enum-based bitmask. We could have just as easily made them “regular” functions, and it becomes easier to visualize how “programmable DCE” happens:

new Socket(
    "127.0.0.1",
    8081,
    Socket.WEBSOCKETS() | Socket.IE6() | Socket.IE7()
);

Remember the basic principle of DCE: if a function isn’t called, it isn’t included in the final output. When you view the above code as function calls – rather than bitmasks – you can begin to visualize how we can enable the user to customize the polyfills she wants. If the user did not call Socket.IE6(), the IE6 polyfills will not be included.

Even if your function is a 1000+ line monster with complex polyfill code, if it isn’t called, it isn’t compiled.

The Programmable DCE Pattern

In a nutshell, programmable DCE happens like this:

  1. Define a private static polyfill method.
  2. Define a public static getter that returns a bitmask-compatible value and invokes the relevant private static polyfill method.
  3. Repeat steps 1-2 for each browser/polyfill you need to support.
  4. Define a constructor that accepts bitmasked options.

Everything is perfectly encapsulated. When the user instantiates your class, they will need to use the bitmask. The bitmask values invoke getters with custom logic. The custom logic invokes the polyfills the user needs.

JS++ 0.7.0: JavaScript Fully Implemented

JS++ 0.7.0 has arrived. Everything that is possible to do in JavaScript is now possible to do in JS++. JS++ has fully implemented JavaScript and the JS++ Standard Library is now fully documented.

This means that every JavaScript feature you expect is now available in JS++: arrays (0.7.0 introduces the generic Array<T> class), functions, date/time, regular expressions, loops, bitwise operators, etc. This is in addition to several JS++-only features: foreach, modules, classes, imports, enums, virtual functions, integer types, optimized auto-boxing, function overloading, dead code elimination (DCE), and so on.

You can find all the current Standard Library documentation by clicking here. Every documented class, method, and field (with examples) should be available and work in 0.7.0.

System.Array<T>

The major missing feature for a while now has been arrays. JS++ 0.7.0 brings the generic System.Array<T> class to JS++. With this addition, everything you can do in JavaScript is possible in JS++.

The full documentation for System.Array<T> is available here.

Additionally, JS++ adds more features to the Array API that aren’t available in JavaScript such as clear, contains, remove, first, last, count, and more. These methods are all optimized; in other words, there is no performance overhead in using them. In addition, we benchmark each method to make sure we are always providing the fastest implementation for an abstraction you want.

System.Array.sort and IComparable<T>

It comes as no surprise that JavaScript has strange behavior. Consider this JavaScript code:

var arr = [ 1, 2, 10, 9 ];
arr.sort();
console.log(arr); // [ 1, 10, 2, 9 ]

As you can see, JavaScript did not sort the numeric array correctly. The reason for this behavior is because JavaScript performs a string sort regardless of the types in the array. Since JS++ is statically-typed, we can generate code for a correct sort with zero overhead. In JS++, the System.IComparable<T> interface provides exactly this behavior. If a class implements System.IComparable<T>, it can provide custom sorting behavior.

All Standard Library wrapper classes implement System.IComparable<T>. Thus, all JS++ numeric types will be sorted numerically when used inside an array – as you would expect from a modern, well-designed language. Here’s an example:

import System;

int[] arr = [ 1, 2, 10, 9 ]; // make sure you use an internal type like 'int[]' and not an external type like 'var'
arr.sort();

And here’s the generated code:

// Compiled with JS++ v.0.7.0
! function() {
    ! function() {
        var arr = [1, 2, 10, 9];
        arr.sort(function(a, b) {
            return (a - b);
        });
    }();
}();

As you can see, there is zero overhead – despite the complex inheritance hierarchy (int[] being auto-boxed by System.Array<int>, System.Array<int> providing a custom sort based on generic type constraints, and System.Integer32 implementing IComparable<T>).

ECMAScript 5 Array Methods

ECMAScript 5 (ES5) added several array methods:

  • indexOf
  • lastIndexOf
  • every
  • some
  • filter
  • map
  • forEach
  • reduce
  • reduceRight

However, these methods are not supported in older web browsers. JS++ aims for enterprise support and legacy web application support. However, in order to polyfill these methods, it would result in hundreds of lines of code. Thus, in the spirit of JS++ dead code elimination (DCE), the above methods are only polyfilled for incompatible web browsers if and only if the individual method is used.

System.Object

One peculiar Standard Library class you might notice is System.Object. Specifically, it does not implement the JavaScript API at all. This is because JS++ does not use prototypical inheritance like JavaScript does. JS++ uses class-based inheritance; thus, System.Object is minimal and does not provide methods that are only useful for a prototype-based language – such as hasOwnProperty and isPrototypeOf.

JS++ uses a “Unified Type System” (like Java/C#) with System.Object at the top of the inheritance hierarchy. Thus, System.Object represents all “internal types.” If you don’t know what that means, please fully read the “Getting Started” guide.

If you want to use JavaScript objects, you still have to declare external types until System.Dictionary<T> arrives:

var obj = {
    "a": 1,
    "b": 2
};

In addition, if you want the JavaScript Object prototype methods, use the Externals.JS module:

import System;
import Externals.JS;

Console.log(typeof Externals.JS.Object.prototype.hasOwnProperty == "function"); // true

Prefer the Standard Library

There are 300+ pages of Standard Library documentation (not including all the documentation for individual method overloads). This is in addition to 300+ pages of handwritten documentation, bringing the JS++ documentation to over 600 pages.

As always, I recommend that you prefer the JS++ Standard Library to writing your own JavaScript implementation. Consider clearing an array. In JS++, the code is:

arr.clear();

You might be tempted to avoid the function call overhead and try to roll your own JavaScript:

arr = [];

First of all, this can create a memory leak (e.g. if other references to the original array are being held). The JS++ Standard Library provides high-quality, fast, and well-tested functions to you. Use it.

Secondly, what looks like function call overhead on the surface is actually inlined, correct code in the final output:

arr.length = 0;

Arrays have incredibly low overhead. Here’s the full code:

import System;

int[] arr = [1,2,3];
arr.clear();

Here’s the generated output:

// Compiled with JS++ v.0.7.0

!function(){!function(){var arr=[1,2,3];arr.length=0;}();}();

As you can see, there is zero overhead. Thus, use the Standard Library. Don’t try to be fancy and write JavaScript rather than JS++ code. Your users’ garbage collectors will thank you for it in the future when you’re not leaking 500mb of RAM, and your team will thank you for it because .clear() is A LOT more readable than .length = 0 and A LOT more correct than arr = [];

Code Readability

One of the major driving changes for JS++ is code readability. We invest heavily into this from cutting-edge parsers to Standard Library design. The JS++ Standard Library allows you to write high-performance, readable code.

Consider this JavaScript code:

var abc = [ "a", "b", "c" ];
abc.splice(1, 1);

Without evaluating it, what do you think it does?

Here’s the equivalent JS++ code:

string[] abc = [ "a", "b", "c" ];
abc.remove(1);

Same code. Same performance. Many times more readable when written in JS++.

Looking Ahead

We’re going to continue to expand the JS++ Standard Library to provide useful functions and give you a “batteries included” experience. Additionally, we’ll continue to expand the language. The following features are still not implemented:

  • User-defined Generic Classes
  • Reflection API
  • System.Dictionary (hash maps)
  • Block Scoping
  • Nullable Types
  • final variables (but final classes and methods are done)

If you have a pressing need for any of these features, you may want to wait. However, everything that is possible to do in JavaScript is now possible to do in JS++.

Compiler Architecture: Efficient Module Resolution for Context-Sensitive Grammars with Cyclic Dependencies

The JS++ programming language and compiler present unique engineering challenges. In my previous “Under the Hood” post, I discussed GLR parsing and disambiguation. Today, I will be discussing JS++ importing and the compiler architecture.

The JS++ import system efficiently supports features such as being decoupled from the file system and circular imports on an ambiguous context-sensitive grammar (CSG).

An example of tight coupling with the file system would be Java or ActionScript. If you define a class named utils.myapp.myclass, the file and directory structure would need to reflect this. This tight coupling presents problems during refactoring. If you change the name of a class or package/namespace, you would have to rename everything in the file system too. CommonJS, originally used by Node.js and RequireJS, suffered from a similar weakness.

When the import system is tightly coupled with the file system, resolving imports, modules, and files are an O(1) operation: just open the file based on its fully-qualified name. In JS++, resolving an import risks being an O(N2) operation where, for each import on each file, every other input file needs to be opened, parsed, and searched to find if a module was declared in the input file (or if the module was declared at all… in any input files).

In addition, JS++ faced an additional engineering challenge by enabling circular imports on an ambiguous grammar. Consider the following code:

Foo < bar > baz;

Is the above code a variable declaration to declare a variable named baz with type Foo<bar> or is it a comparison expression statement? Java and C# solve this ambiguity by simply restricting such “expression statements” from being statements to enable generic programming. However, JS++ inherited the JavaScript syntax, and it would not be ideal to have to break existing code and valid syntax that users already know.

The above code can be disambiguated if we know whether Foo is a generic class or not. If Foo is a generic class, the code is a variable declaration; otherwise, it is a comparison expression. This sounds simple in theory, but – in practice – what if Foo is declared in another module? Sure, you can import all modules first (and that comes with deeper questions such as what level of analysis or code generation do you want to perform prior to importing). However, the reality is not so simple. What if Foo is declared in another module, and we want to import it, but the other module has a circular dependency to the current file? Which one do we import first? How do we do all of this efficiently so that we don’t basically process a file more than once?

The JS++ compiler does not require you to specify the import and linking order during compilation. You can store all your *.jspp files in one directory and compile like so:

$ js++ .

There was no existing literature available. No existing language’s import system faced all the challenges that we faced (such as inheriting unorthodox semantics from JavaScript like function hoisting) or had the same design as we did. Internally, from an engineering perspective, we also wanted to reduce or eliminate “branching logic” in the compiler logic.

Thus, without the user specifying the import order, with circular imports on an ambiguous grammar being allowed, with no dependency on the file/folder structure, having to be compatible with JavaScript, and having to be as fast as possible (preferably without caching), how does the JS++ compiler do it?

Preface: The JS++ Import System

Users of JS++ can admire the ease of use. Unlike JavaScript, the JS++ import system is very simple:

A.jspp

module Utils.Strings
{
    bool isEmpty(string s) {
        return s == "";
    }
}

B.jspp

import Utils.Strings;

isEmpty("");    // true
isEmpty("abc"); // false

The JS++ import system has several advantages to JavaScript’s:

Syntax and Brevity

First of all, you may immediately notice the conciseness. Prior to ES6, JavaScript had no modules and you had to use ad-hoc import systems. In ES6, when you define a module, you must explicitly declare the items you want to export. In contrast, JS++ will automatically “export” all your modules. The next thing you will notice is that JS++ also automatically imports all module members. In JavaScript, you would need to manually specify the specific members you want imported (or use a wildcard).

Efficiency

While JS++ may automatically “export” everything and subsequently “import” everything, it is very efficient. In a process known as dead code elimination, JS++ will “eliminate” unused code from the final output. For example, if your module defines three functions A, B, and C and you only use function A, then B and C will not be compiled in the final output. In addition, if you import a module but never use anything from the module, the entire module will simply not be generated.

Simplicity

Another benefit of the JS++ module and import system is simplicity. Consider all of the “overloads” of the ECMAScript 6 import keyword:

import * as myModule from 'my-module';
import {myMember} from 'my-module';
import {foo, bar} from 'my-module';
import {reallyReallyLongModuleMemberName as shortName}
  from 'my-module';
import {
  reallyReallyLongModuleMemberName as shortName,
  anotherLongModuleName as short
} from 'my-module';
import 'my-module';
import myDefault from 'my-module';
import myDefault, * as myModule from 'my-module';
// myModule used as a namespace
import myDefault, {foo, bar} from 'my-module';
// specific, named imports

Source: MDN

All of the above syntaxes do something different in JavaScript. In contrast, JS++ has only one import statement syntax:

import moduleName;

Decoupling

I once received a user question about why we don’t specify file/directory structure and naming conventions. The reason is because we give you absolute liberty here, and this actually comes from the software architecture. If you want your code to reflect the file/folder structure (a la Java), you’re free to do that. If you want all your code in one folder, you’re free to do that. However, we do specify a naming convention for modules in our documentation here.

Step 1. Parsing and Symbol Table Construction

The JS++ project is composed of several projects: the compiler, the parser, and so on. Prior to adding the import and module keywords in JS++ 0.4.2, the only project within JS++ using a symbol table was the compiler (for type checking). We began by decoupling the symbol table and refactoring it into a separate project as both the parser and compiler would depend on the symbol table.

Beginning from JS++ 0.4.2, the symbol table construction starts at parse time. Since the JS++ compiler allows you to use an entire directory as input (and it will recursively find all *.jspp and *.jpp files), we start by reading and parsing all input files. While we are parsing the input files, we build the symbol table and mark the symbols that cannot be currently resolved using a temporary meta-symbol such as <RELOCATE> or <UNRESOLVED>.

This process especially applies to “partially-qualified” names in JS++. This is what partial qualification looks like:

import Utils.Strings;

// Partial Qualification:
isEmpty("");    // true
isEmpty("abc"); // false

// Full Qualification:
Utils.Strings.isEmpty("");    // true
Utils.Strings.isEmpty("abc"); // false

In the above code, the identifier isEmpty can come from anywhere. It can even come from a module requiring circular imports. However, rather than processing the imports at this time, we simply mark the isEmpty identifier as unresolved for now. In addition, this allows us to deal with strange semantics that we inherited from JavaScript such as hoisting. In the case of hoisting, we might mark an identifier as unresolved even if it comes from the same file but gets declared later.

At this stage, the types of operations that may cause a symbol table insertion are “declarations” such as:

  1. Variable Declaration
  2. Function Declaration
  3. Function Parameter
  4. Module Declaration
  5. Label Statements (e.g. when labelling ‘for’ loops)
  6. Catch parameter (from try-catch blocks)
  7. External Statement (external foo;)
  8. Class and Interface Declarations (but this was not done for v.0.4.2)

At this point, no type checking or analysis has been performed. We only identified whether a symbol has been resolved or unresolved.

Step 2. Symbol Resolution

Once we have the basic symbol table built, we need to find all the symbols that need to be resolved and perform symbol resolution. However, we cannot haphazardly resolve symbols based on some “global” symbol table. This will lead to branching logic.

Instead, each resolution is file- and import-sensitive. In other words, we don’t process a “global” symbol table and resolve symbols. We process at the file level. We go through a file, and start by importing all modules based on import statements. Since JS++ imports by identifiers, you can see how finding an associated module or file can now be efficiently done without forcing the user into a Java-like import system that is tightly coupled to the file system.

Keep in mind that the same module “identifier” can be used across multiple files in JS++ because modules are not overwritten – they are “extended.” Nevertheless, it’s still just a symbol table lookup. (While building the symbol table, we can just “extend” the module’s sub-members each time a member is declared in a different file and keep information about which file each individual member is located to use for error reporting.)

Once the symbol is “found”, we replace the type in the symbol table from some unknown or <UNRESOLVED> type to the type of the symbol, and – in JS++ 0.4.2 – we record the pointer to its AST node for code generation (since we did not have an object code or intermediate language yet). If a symbol could not be resolved or if it could be found in one of the files but it wasn’t explicitly imported, we raise an error for undefined symbol.

Other errors that we can discover at this stage might be ambiguous partial qualification or cross-file, cross-module duplicate member declarations such as:

// A.jspp:
module Foo { void bar() {} } // Error, duplicate in B.jspp

// B.jspp:
module Foo { void bar() {} } // Error, duplicate in A.jspp

Step 3. Type Checking and Semantic Analysis

Since all symbols have now been resolved, we can perform type checking and semantic analysis.

At this stage, we don’t need to perform analysis in any particular file order. Thus, we do not need a topological sort (plus there is the chance for circular dependencies) or anything fancy. The JS++ compiler just uses the user-inputted file order here, but any order is fine.

Step 4. Dead Code Elimination

Once all analysis has completed, we also have information on which functions were called, which modules were used, which classes were instantiated. This allows us to perform dead code elimination and other optimizations.

Conclusion

While the problem itself was difficult and entailed many complexities, I’m happy that we were able to create a simple and efficient software architecture.

It might be possible that Java was tightly-coupled with the directory structure because of the engineering and architectural challenges involved in a more complex import system. For example, it should be clear that a custom parser is required, and a parser generator cannot be used. In a more complex grammar, there may be grammatical ambiguities involved. For example, the JS++ grammar cannot be described with a CFG or one-token lookahead. However, all these complexities were essentially covered and considered in the architecture.

In addition, circular imports need to be handled in a manner that is both time and space efficient. This article demonstrated how JS++ handles this without caching, without running a file through the full compile (or even parse) process more than once, and so on.

The JS++ import system is only one aspect of the JS++ compiler architecture. Even in languages that support circular imports, such as C#, they did not have to deal with JavaScript’s history. If you are interested in the challenges we faced in building on top of the JavaScript language syntax, consider reading my first “Under the Hood” series article about grammatical disambiguation.

JS++ 0.5.2: BSD License, Interfaces, Abstract Classes, Virtual Methods, Non-generic Standard Library Classes

You’ve asked and we’ve listened. JS++ is now licensed under the 3-clause BSD License.

When we first announced 0.5.1 back in March, we introduced bare minimum classes. Specifically, I noted the following class features were unavailable:

  • Generic classes
  • Abstract classes
  • Inner classes
  • Interfaces
  • Virtual methods
  • Custom Conversion Rules as defined in my book, “The JS++ Type System”, Chapter 6.2

Every feature in the above list that isn’t crossed out is now available except the last feature (custom conversion rules) which will be arriving next. In addition, today’s release marks the introduction of the Standard Library. I’m going to briefly introduce the new features.

Update to Hello World

The JS++ Hello World program is now written as:

import System;

Console.log("Hello World");

Notice we no longer have to declare console as external. external is used for importing JavaScript libraries, and since we didn’t have a JS++ console implementation yet, we resorted to using the JavaScript console. However, now that we have a Console class in the Standard Library, it’s no longer a problem.

It is always recommended that you use the Standard Library’s Console class over the external JavaScript console. JS++ will detect if a console is available and will not crash if you try to log to an unavailable console. This can be a problem for web browsers like older versions of Internet Explorer, which are still used heavily in enterprise web applications.

Standard Library

The following Standard Library classes are now available:

  • System.Boolean
  • System.Character
  • System.Console
  • System.Date
  • System.Double
  • System.Exception
  • System.Exceptions
  • System.Integer8
  • System.UInteger8
  • System.Integer16
  • System.UInteger16
  • System.Integer32
  • System.UInteger32
  • System.Math
  • System.Object
  • System.RegExp
  • System.String

Many of the above classes, such as System.String and System.Integer32, are wrapper classes for auto-boxing. Currently, these wrapper classes simply provide a type-safe (and sometimes optimized) version of their JavaScript-equivalent methods. For example:

import System;

string s = "my string";
Console.log(s.replace(/^[a-z]/, string(string match){ return match.toUpperCase(); })); // Prints "My string"

The above example provides the exact same functionality as JavaScript’s String.prototype.replace. However, you get safety guarantees that you wouldn’t get with JavaScript. For example, if you try to call System.String.replace using the wrong arguments:

Console.log(s.replace(1));
[  ERROR  ] JSPPE5023: No overload for `System.String.replace' that takes `1' argument(s) at line 4 char 12 at replace.jspp

Optimizations

Always favor using the JS++ Standard Library over “rolling your own” functions. Consider the following code (which you can run yourself with the latest JS++):

import System;

double t = (new Date).getTime();
string z;
for (int i = 0; i < 5000000; ++i) {
	z += Double.POSITIVE_INFINITY.toString();
}
Console.log((new Date).getTime() - t);

And the nearly equivalent JavaScript code:

var t = (new Date).getTime();
var z = "";
for (var i = 0; i < 5000000; ++i) {
	z += Number.POSITIVE_INFINITY.toString();
}
console.log((new Date).getTime() - t);

JS++ average time: 124.4ms
JavaScript average time: 211ms

In this case, JS++ is roughly 70% faster... for nearly identical code.

You may think JS++ adds overhead (based on perceptions of what fast code may look like), but well-written JS++ will be faster than JavaScript. See my other article on optimization for more details.

Typed Exceptions and Multiple Catch Clauses

JS++ 0.5.2 introduces the System.Exception class and enables you to create your own custom exceptions.

Here's an example:

import System;

class CustomException : System.Exception
{
    CustomException() {
        super();
    }
    CustomException(string message) {
        super(message);
    }
}

try {
    throw new CustomException("This is a custom exception object.");
}
catch(CustomException e) {
    Console.log("Caught CustomException");
}
catch(System.Exception e) {
    Console.log("Caught System.Exception");
}

Variadic Parameters

The latest version of JS++ also introduces variadic parameters, which allow you to supply an arbitrary number of arguments to a function:

import System;

void log(Date date, ...string messages, bool silent) {
    if (silent) return;

    foreach(string message in messages) {
        Console.log(date.toString() + ": " + message);
    }
}

log(new Date(), "1", "2", "3", false);

Interfaces

An interface creates a contract. Methods defined in an interface must be implemented by all inheriting classes. Classes can inherit more than one interface.

According to JS++ naming conventions, interfaces should be prefixed with "I" and should be UpperCamelCase.

import System;

interface IWalkable {
	void walk();
}
interface ITalkable {
	void talk();
}

class Person : IWalkable, ITalkable
{
	void talk() {
		Console.log("Talking...");
	}
	void walk() {
		Console.log("Walking...");
	}
}

Person person = new Person();
person.talk();
person.walk();

Callback Type Parameter Names

Callback types can have parameters. Previously, you could only specify the parameter types for a callback/function type. However, you can now add names for these parameters. While these names cannot be used and have no meaningful effect on the executed code, they improve the readability of the code.

import System;

class Bird
{
	void fly() {
		Console.log("Flying...");
	}
}

void(Bird bird) fly = void(Bird bird) {
	bird.fly();
};
Bird bird = new Bird();
fly(bird);

Removal of 'Convert' Module

We have removed from the Convert module from the latest release. It was always used as a stopgap until we implemented the Standard Library wrapper classes, which provide toString() and other methods.

Bug fix: 'typeof' for internal types

For non-external types, typeof will always return the string "internal".

import System;

int x;
Console.log(typeof x); // "internal"

Virtual Methods

JS++ 0.5.2 introduces the virtual keyword and the override keyword to enable virtual methods on classes.

Virtual methods enable late binding and runtime polymorphism.

class Shape
{
    public virtual double area() {
        return 0;
    }
}
 
class Rectangle : Shape
{
    private int length, width;
 
    public Rectangle(int length, int width) {
        this.length = length;
        this.width = width;
    }
 
    public override double area() {
        return length * width;
    }
}
 
class Triangle : Shape
{
    private int base, height;
 
    public Triangle(int base, int height) {
        this.base = base;
        this.height = height;
    }
 
    public override double area() {
        return (base * height) / 2;
    }
}

Abstract Classes

Use the abstract modifier to create abstract classes and methods.

abstract class Shape
{
    public abstract int area();
}
class Rectangle : Shape
{
    private int length, width;
 
    public override int area() {
        return length * width;
    }
}

Enumerations

Enumerations (enums) can be used to restrict values and write type-safe code:

enum Importance { None, Regular, Critical }
 
Importance errorLevel = Importance.Critical;

The one missing feature...

Sadly, there is still one major missing feature from JS++. The Standard Library does not support System.Array yet because it is a generic class, and generics have not yet been implemented. In the meantime, you can resort to declaring your arrays as var:

var arr = [ 1, 2, 3 ];

BSD License

Last, but not least, JS++ 0.5.2 is the first version of JS++ licensed under the 3-clause BSD License.

The download for JS++ 0.5.2 is available from our home page.

Enjoy JS++!

Code Written in JS++ Can be Significantly Faster than the Equivalent JavaScript

JS++ type guarantees don’t just mean more reliable applications. They can also mean faster applications.

People have expressed concern about the “conversion overhead” that comes with the JS++ type system. However, we’ll show you today that having code that varies in type (such as JavaScript code) can be substantially slower, and even if you lose 1ms in JS++ “conversion overhead”, you may gain 10ms, 100ms, or more from typed optimizations that you can only get with JS++.

Here are two side-by-side benchmarks:

JS++: test.jspp

import System;

double t = (new Date).getTime();
string z;
for (int i = 0; i < 5000000; ++i) {
	z += i.toString();
}
Console.log((new Date).getTime() - t);
$ time node test.jspp.js
484

real	0m0.537s
user	0m0.496s
sys	0m0.100s
$ time node test.jspp.js
487

real	0m0.536s
user	0m0.500s
sys	0m0.096s
$ time node test.jspp.js
488

real	0m0.536s
user	0m0.508s
sys	0m0.088s
$ time node test.jspp.js
486

real	0m0.534s
user	0m0.480s
sys	0m0.116s
$ time node test.jspp.js
484

real	0m0.533s
user	0m0.496s
sys	0m0.096s

JavaScript: test.js

var t = (new Date).getTime();
var z = "";
for (var i = 0; i < 5000000; ++i) {
    z += i.toString();
}
console.log((new Date).getTime() - t);
$ time node sample.js 
523

real	0m0.575s
user	0m0.572s
sys	0m0.076s
$ time node sample.js 
518

real	0m0.561s
user	0m0.556s
sys	0m0.072s
$ time node sample.js 
524

real	0m0.572s
user	0m0.544s
sys	0m0.092s
$ time node sample.js 
521

real	0m0.565s
user	0m0.560s
sys	0m0.076s
$ time node sample.js 
519

real	0m0.563s
user	0m0.540s
sys	0m0.088s

Specifications:
Core i7-4790k
Linux x64 (Debian)
32gb RAM
Node.js v.7.9.0 (Google V8)
JS++ v.0.5.2

Take a close look at the JS++ code and the JavaScript code. They are nearly identical except the JS++ code has types and an import statement.

In this particular case, JS++ is roughly 7.2% faster than JavaScript on a basic toString() benchmark. We do some special things under the hood here, but it should be clear that even with the perceived overhead of JS++ conversions and the much heavier overhead of auto-boxing, JS++ code is still noticeably faster. However, the topic of today's post is not about toString(). If we slightly change the JavaScript code:

var t = (new Date).getTime();
var z; // variable is no longer initialized to string
for (var i = 0; i < 5000000; ++i) {
	z += i.toString();
}
console.log((new Date).getTime() - t);
$ time node sample.js 
735

real	0m0.779s
user	0m0.804s
sys	0m0.072s
$ time node sample.js 
735

real	0m0.783s
user	0m0.784s
sys	0m0.092s
$ time node sample.js 
749

real	0m0.794s
user	0m0.824s
sys	0m0.088s
$ time node sample.js 
742

real	0m0.787s
user	0m0.788s
sys	0m0.092s
$ time node sample.js 
738

real	0m0.782s
user	0m0.808s
sys	0m0.064s

Suddenly, JS++ has jumped from being ~7% faster to being 52.2% faster.

First of all, without static typing, you lose correctness. The result of the above small change results in "undefined0123..." rather than "0123...". Therefore, while it may not be the best benchmark, it illustrates the point. Besides losing correctness, the drop in performance is substantial when types change. You often see JavaScript code written where the type constantly changes, and you can see the cost of this negligence compared to JS++.

The reason this happens is because V8 optimizes "optimistically". When you initialize your variable to a string, V8's JIT code generator will generate code optimized for strings. However, when the type changes, V8 has to "de-optimize", change the variable type, convert data, and more. These are expensive operations which highlight how performance can degrade. The example we showed today involved only one variable. Imagine the performance difference in an application with thousands of variables.

Finally, the JS++ type system is patent-pending. I've made my case clear about patents being only used for competition. Since most programmers immediately jump to conclusions, I will use this example: you can use a patented skateboard without getting in trouble with the law; however, you cannot make and sell a patented skateboard without getting in trouble with the law. If you're on the fence with JS++, don't expect to see our technologies in TypeScript, Flow, or any competing language any time soon. You're free to use them, and we encourage you to do so if your only criteria when selecting technologies are "open source" and "unpatented."

JS++ is free, closed-source software licensed under the BSD License, and the benchmarks above can be executed with the latest JS++ 0.5.2 release.

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!

JS++ 0.5.1: ‘foreach’

We just released JS++ 0.5.1, which features the foreach keyword.

Basic usage is as follows:

external console;

int[] arr = [ 50, 40, 30 ];

foreach (int value in arr) {
    console.log(value);
}

// Output:
// 50
// 40
// 30

More complex usage, such as arrays of objects, are also possible:

external console;

class Foo
{
	string bar() {
		return "bar";
	}
}

Foo[] foo = [ new Foo(), new Foo(), new Foo() ];

foreach (Foo value in foo) {
    console.log(value.bar());
}

// Output:
// "bar"
// "bar"
// "bar"

Additionally, the for-in keyword has been implemented. It is a counterpart to the foreach keyword in the sense that it enumerates keys rather than values.

JS++ 0.5.0: Basic Classes

JS++ now supports the ‘class’ keyword. As promised, we would have classes available by Q1 2017. Notably, we are providing “basic” classes, so the following features are supported:

  • ‘class’ keyword
  • Inheritance
  • Constructors (including private/protected constructors that limit instantiation/inheritance)
  • Static Constructors
  • Instantiation
  • Fields
  • Methods
  • ‘this’ keyword
  • ‘super’ keyword
  • Method Overloading
  • Constructor Overloading
  • Getters and Setters (via ‘property’ keyword)
  • Type system support
  • Debugger support for classes (via source maps)

What did we consider to be outside the scope of basic classes? The following features are currently not available yet:

As an example of what you can do with JS++ classes, we included an example with the Tiled Map Editor:

Tiled Map Editor

The included sample for Tiled can be found in the ‘Samples/Classes/tiled-loader’ directory with JS++ 0.5.0. Currently, it will load all maps exported to JSON with orthogonal tiles. It’s just a small but powerful example of what you can start doing with JS++ for early adopters.

I am also happy to inform that the backend for the JS++ website is written completely in JS++, and it has now run stable for one week without a single crash or error (other than 404 errors).

Finally, we have made the decision to not include the Mac/Linux installer… yet.

Be sure to check out the documentation on the ‘class’ keyword to get up to speed on JS++ classes.

Download JS++ 0.5.0 from our home page.