JS++ 0.8.10: Faster Compile Times, Stacks/Queues, Unicode, Base64, and More

The next version of JS++ (not this one) will be a breakthrough. It is on par with ‘external’ in its importance to JS++. Stay with us, and stay tuned.

In this latest release of JS++, we’ve done a lot: we’ve improved on our compile times which already lead the competition by an order of magnitude (with room for more improvement), we’ve substantially expanded the Standard Library, made a UX improvement to generics (without breaking any existing code), and we’ve fixed a lot of bugs (which are mostly minor at this point after years of engineering).

Faster Compile Times

import System;

Console.log("Hello World");

On the Core i7-4790k:

Version Total Time
JS++ 0.8.5 96.2ms
JS++ 0.8.10 72.6ms
(Lower is better)

System Specifications:

  • Intel Core i7-4790k
  • 32gb DDR3 RAM
  • Samsung 960 EVO M.2 SSD

As evidenced in the table above, the latest version is now compiling “Hello World” 32.51% faster. There is still room for more improvement to compile times, but it is not our current priority. We improved compile times in this release by pre-parsing and caching the JS++ Standard Library. There is more to Standard Library compilation than this single step, but we wanted to address this problem as it was the largest performance regression in our profiling. Practically, this allows us to substantially expand the JS++ Standard Library with an O(log N) cost to compile times versus the previous O(n) cost of adding new libraries.

And because we’re able to add substantially more libraries… we’ve done exactly that.

System.Stack<T> and System.Queue<T>

JS++ now provides stack (LIFO) and queue (FIFO) data structures. Stacks are an abstraction over JavaScript arrays and are very fast.

import System;

auto stack = new Stack<int>();
stack.push(1);
stack.push(2);
Console.log(stack.pop()); // 2

In the generated code, the ‘push’ call is a direct ‘push’ call on the internal array representation behind the stack so there is no performance loss in using the stack abstraction instead of arrays.

Next, we also have queues via System.Queue. It’s not as simple as an abstraction over JavaScript arrays like stacks because re-indexing an array would be an O(n) operation. Instead, to guarantee O(1) pop operations, we use a ring buffer. (Credit goes to Anton, our lead engineer.)

import System;

auto queue = new Queue<int>();
queue.push(1);
queue.push(2);
Console.log(queue.pop()); // 1

At a micro-optimization level, you might question our decision on the ring buffer backing store. However, computer science is important. If you take a look at my JS++ stringset library, you’ll see this benchmark over a dictionary of ~49,000 terms:

StringSet : 70ms     (00.07 seconds)
string[]  : 82299ms  (82.29 seconds)

Clearly, the performance difference here is substantial, but it should be no surprise to anyone that understands data structures: an array has O(n) lookups, and a set has O(1) lookups.

Documentation:

System.Encoding

This module introduces a lot of useful new features, but I’m going to break it down.

Base64 Encoding and Decoding

A common operation in web development is Base64 encoding and decoding. For example, the HBase REST API requires Base64 encoding/decoding. You can also use Base64 to encode binary data and files as ASCII, such as converting canvas image data into data URIs.

Wouldn’t it be nice to have all of this functionality readily available in the language you use?

import System;
import System.Encoding;

string quote = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";

string encoded = Base64.encode(quote);
Console.log(encoded);

string decoded = Base64.decode(encoded);
Console.log(decoded);

The more you master JS++ and know how to use the Standard Library, the more efficiently you can get work done compared to JavaScript.

Documentation: System.Encoding.Base64

UTF-8, UTF-16, and UTF-32

Dealing with Unicode is a key aspect of writing world-ready software. UTF-8, UTF-16, and UTF-32 are encoding schemes defined in the Unicode Standard, and JS++ now supports encoding and decoding of all of these in the System.Encoding module.

Here’s an example of UTF-8 encoding:

import System;
import System.Encoding;

byte[] encoded = UTF8.encode("€");

string toHex = "";
foreach(byte b in encoded) {
    toHex += "\\x" + b.toHex().toUpperCase();
}

Console.log(toHex); // "\xE2\x82\xAC"

We just want to take a moment to remind you the importance of the JS++ type system in scenarios like this and how it naturally interoperates with so many areas of computing. In this case, the ‘byte’ data type is a natural fit for dealing with standard Unicode encoding schemes.

Documentation:

URI Encoding and Decoding

This module provides the ECMAScript 3 encodeURI, encodeURIComponent, decodeURI, and decodeURIComponent functions.

Documentation: System.Encoding.URI

Superior Documentation

Documentation is one of the strengths of JS++. We have over 600+ pages of handwritten documentation.

With the release of the System.Encoding.URI module, we wanted to expand on this. Have you ever wondered about the difference between encodeURI and encodeURIComponent in JavaScript? This unfortunate naming scheme, dating back to ECMAScript 3, is a source of confusion. Developers often cite the Mozilla Developer Network (MDN) for documentation, but their explanation is equally as confusing as the naming scheme and lacks useful information:

encodeURIComponent

Stack Overflow wasn’t tremendously more helpful either, and most answers once again just go over which characters get converted and which do not. This doesn’t help the practicing developer learn or memorize which function to use.

Fortunately, JS++ has you covered. We explain the difference between encodeURI and encodeURIComponent clearly, and we also provide an explanation of best practices to help you navigate the confusion:

https://docs.onux.com/en-US/Developers/JavaScript-PP/Language-Guide/encodeuri-vs-encodeuricomponent

Improving Generic Programming UX: Default Constraint

We’ve improved the user experience (UX) for generic programming in JS++.

Previously, the default constraint for generic type parameters was System.Object. However, for performance reasons, the default constraint did not allow primitive types. For example:

class Foo<T> // same as 'Foo<T: System.Object>'
{
}

auto foo = new Foo<string>(); // ERROR (previously)

Instead, you needed to specify the “wildcard constraint” (see the docs) if you wanted to allow primitive types as arguments, as System.Array and System.Dictionary do.

However, this was not the most useful default. All your old code will still work, but we just made the defaults more useful. Starting from version 0.8.10, all your generic classes will have the wildcard constraint as the default. You can declare a plain generic class and instantiate it with primitive types as type arguments.

‘this’ Semantics

First and foremost, before we announce this change, we have to say all semantics relating to this are subject to change.

We’ve been well aware of how JavaScript’s this rules differ from the semantics that users from other programming languages are familiar with. However, previous versions of JS++ raised a ‘0000’ (unimplemented) error here, and the fix was non-obvious:

class Foo
{
    string message = "Test";
    void bar() {
        $(document).click(void() {
            $("#button").text(this.message); // JSPPE0000 error
        });
    }
}

You had to manually capture the ‘this’ value for closures inside classes:

class Foo
{
    string message = "Test";
    void bar() {
        Foo _this = this;
        $(document).click(void() {
            $("#button").text(_this.message); // OK
        });
    }
}

First of all, I apologize for the cryptic error message. We work very hard to make sure our error messages are easy to understand, and we always try to suggest the fix in the error message itself where possible. In this case, we always thought the ‘this’ semantics would be settled within a reasonable time and thought the “unimplemented” error would only be temporary. We were wrong. Thus, it’s important to know we may change the rules and semantics again prior to JS++ 1.0.

In the current release, the this keyword – when used inside classes – refers to the class instance by default. There are cases where you might want it to retain JavaScript this semantics, and, at least for closures inside classes declared with the function return type, you can cast it to external:

class Foo
{
    string message = "Test";
    void attachEvents() {
        $("#button").click(function() {
            var $this = (external) this;
            $this.text(this.message); // OK
        });
    }
}

We are open to input on this functionality.

You can review our plans on the this documentation page under the header, “‘this’ Casting inside Classes”.

Bug Fixes

  • Disable auto creation of the arguments object
  • File extensions are case-insensitive
  • Fix crash during access to a property with undeclared type (reported by @lorveg in JS++ chat)
  • Fix contravariance check in foreach loop
  • Incorrect scoping and code generation for ‘external’
  • Segfault for interface with generic variants
  • Fix missing class name for inheritance in error message

Tips & Tricks: Overriding ‘toString’

JS++ has a default ‘toString’ method implementation but, sometimes, it is necessary to override this implementation. For example, when using Console.log, it may be desirable to be able to fully log and inspect a complex JS++ object.

In addition to the Unified External Type, there is also a “Unified Internal Type”: System.Object. All JS++ classes, including user-defined classes, inherit from System.Object. Due to auto-boxing, even primitive types such as int (wrapped by System.Integer32), inherit from System.Object.

Aside: Don’t worry about the performance implications of auto-boxing. JS++ is able to optimize auto-boxing to the point that toString is actually 7.2% faster in JS++ than JavaScript in the worst case (assuming the JavaScript variable is monomorphically-typed) and more than 50% faster for polymorphically-typed (and potentially type-unsafe) JavaScript variables as shown in benchmarks here.

System.Object has a toString method which is marked as virtual. In other words, this method can be overridden by derived classes – which are effectively all classes in JS++. Here’s an example of how to do it:

import System;

class Point
{
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    override string toString() {
        return "(" + x.toString() + ", " + y.toString() + ")";
    }
}

Point p = new Point(1,2);
Console.log(p); // "(1, 2)"

You’ll notice the Console.log statement doesn’t even make an explicit toString call. The reason is because passing any JS++ object to Console.log will call the toString method on the object for you.

Join the JS++ Chat Room

If you need instant help or just want to talk about JS++, feel free to join us in the JS++ Chat Room:

https://chat.onux.io/signup_user_complete/?id=6eoxd4erotgwdgin8p6x9uupyc

The special thing about this chat room is that our internal team uses this chat software to collaborate. While we are mostly in private channels, we are almost always available in the public chat rooms. If you need help, you can get help instantly from the creators of JS++.

Tips & Tricks: fromExternal/toExternal Design Pattern

JS++ provides toString and fromString (one example) methods in the Standard Library. However, it can be argued that the external type is just as important or even more important in JS++ as string.

We introduce a design pattern for converting complex user-defined JS++ types (such as classes) to JavaScript.

toExternal

You can define a toExternal method that enables you to convert an object of an internal type to external:

import System;

class Point
{
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    function toExternal() {
        return {
            x: x,
            y: y
        };
    }
}

Point p = new Point(2, 3);
var p2 = p.toExternal(); // conversion to 'external'
Console.log(p2.x); // 2
Console.log(p2.y); // 3

fromExternal

Likewise, you can convert incoming JavaScript data to a complex, user-defined JS++ type:

import System;
import System.Assert;

class Point
{
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    static Point fromExternal(obj) {
        assert(typeof obj == "object", "Expected external 'object' type");
        assert(typeof obj.x == "number", "Expected incoming external to have numeric 'x' property");
        assert(typeof obj.y == "number", "Expected incoming external to have numeric 'y' property");
        return new Point(Integer32.fromString(obj.x), Integer32.fromString(obj.y));
    }
}

Point p1 = Point.fromExternal({ x: 2, y: 3 });
// Point p2 = Point.fromExternal({ x: "x", y: 3 }); // this will fail
// Point p3 = Point.fromExternal({ x: 2, y: "y" }); // this will fail

Protecting References

For functions, you don’t want to send out a direct reference to external JavaScript. Otherwise, external JavaScript code can modify the JS++ reference in unsafe ways. Therefore, you should wrap the function using closures:

class Foo
{
    void bar() {}

    function toExternal() {
        Foo self = this;

        return {
            bar: void() {
                self.bar();
            };
        };
    }
}

Likewise you can clone arrays and other containers depending on the level of trust and safety you desire.

Tips & Tricks: Only Fields are ‘private’ by Default

Programmers often complain about the verbosity of Java. Once you specify all the modifiers that must be applied, it’s not difficult to see how it can quickly become verbose:

public static void veryLongNamingConventions() {
    // ...
}

JS++ does this differently. Following the OOP principle of encapsulation, JS++ provides convenient default rules for access modifiers.

By default, only fields (variable members of classes) are private. All other class members – such as methods, getters, setters, and constructors – are public by default.

This makes it very easy to write concise code:

class Point
{
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    int getX() { return this.x; }
    int getY() { return this.y; }
}

In the above code, the fields x and y are private. Meanwhile, the constructor and the getX/getY methods are all public. We can be explicit and manually specify the access modifiers, but it’s not necessary in JS++.

JS++ 0.8.5: Bug Fix Release

This is a small bug fix release.

The following minor issues have been fixed:

  1. Dictionary expression of empty arrays now has the correct type inferred
  2. Labels for foreach statements
  3. Type inference for System.Array.reduce
  4. Function inlining for System.String methods: padRight(int), padLeft(int), startsWith, endsWith

Issue #1:

Dictionary<unsigned int[]> x = {
    "foo": (unsigned int[]) [],
    "bar": (unsigned int[]) []
};

The casts were previously required in 0.8.4, but, in the latest release, casting of empty arrays is no longer necessary.

Issue #2:

outerLoop: foreach (var row in json) {
    // ...

    foreach(var cell in row.Cell) {
        // ...
        continue outerLoop;
    }
}

Issue #3:

string[] keys = dict.keys();
int x = keys.reduce(
    int(string previous /* type of 'previous' param */, string current) {
    },
    0 // and this type
);

In the above case, the two types must match. However, the type checker was inferring ‘external’ instead. This has been fixed in the latest release.

JS++ 0.8.4: Advanced Generics and System.String Expansion

We have significantly expanded the Standard Library with this release. In particular, System.String has undergone significant expansion.

System.String Highlights

between

string quotedWords = '"duck" "swan" "crab"';
// 'between' is smart enough to allow the same string to be used as a start and end delimiter
string[] words = quotedWords.between('"', '"');
Console.log(words); // [ "duck", "swan", "crab" ]

Documentation page: click here

format: C-like printf

"%s is %d years old".format("Joe", 10) // Joe is 10 years old

Documentation page: click here

escape

"a\r\nb".escape() // a\\r\\nb

Documentation page: click here

truncate

string text = "The quick brown fox jumped over the lazy dog.";
 
Console.log(text.truncate(9)); // "The quick..."

Documentation page: click here

repeat

"*".repeat(5) // *****

Documentation page: click here

count

"foobar".count("foo") // 1
"FOOBAR".icount("foo") // 1

Documentation (count): click here
Documentation (icount): click here

contains

"abc".contains("b") // true
"ABC".icontains("b") // true

Documentation (contains): click here
Documentation (icontains): click here

New System.String Methods

Here are all the new methods available for strings in JS++:

  • between – Gets substrings between two delimiters (does not use regex)
  • compact – Removes whitespace globally
  • contains/icontains
  • count/icount
  • countLines
  • countNonEmptyLines
  • startsWith/endsWith
  • escape/unescape – Escape the escape sequence characters (e.g. \n -> \\n)
  • escapeQuotes/unescapeQuotes
  • format – Similar to C’s printf
  • insert/append/prepend
  • isEmpty – uses .length === 0 rather than str1 === “” for performance, not everyone has time to benchmark every detail
  • isLowerCase
  • isUpperCase
  • isWhitespace
  • joinLines – collapses a string composed of multiple lines into a single line
  • joinNonEmptyLines
  • padLeft/padRight – remember the NPM debacle?
  • quote/quoteSingle – wraps the string in quotes
  • unquote – removes quote pairs
  • repeat – “*”.repeat(3) == “***”
  • reverse
  • splitLines – splits a string into a string[] (array) based on newlines
  • trim, trimLeft, trimRight, trimMulti, trimMultiLeft, trimMultiRight
  • truncate – Cuts off the string at the specified length (with support for custom ellipsis)

There are close to 50 new string methods (48 including overloads, 39 otherwise), and these methods should cover most application-level usages. With documentation, this resulted in +1400 new lines of code to System.String. I’m happy to announce we actually still have more methods (for System.String and others) on the way.

Every single method is documented. All documentation is online and available at the System.String index page.

We avoided regular expressions as much as possible to avoid runtime FSM construction, which takes time and space. Therefore, prefer JS++ methods such as "abc".endsWith("c") over the traditional regex/JavaScript /c$/.test("abc").

The best thing about JS++ is that it’s a compiled language. This gives you performance benefits that a JavaScript library with string utilities can never give you. For example:

if ("abc".isEmpty());

becomes:

if ("abc".length===0);

and

"abc".quote()

becomes:

'"'+"abc"+'"'

The astute observer will notice that both the above methods can be further optimized to reach “perfect” optimization. However, there is no optimizing compiler inside JS++ yet, and inserting branching logic into the code generator will result in technical debt.

Our goal with the Standard Library is to make it easier than ever to write applications compared to JavaScript. Side effects of our work on the JS++ Standard Library are performance, size, and correctness. JS++ dead code elimination means we can add hundreds of methods to System.String, but you only pay for the methods you actually use. For performance, not every team can afford to hire a JavaScript performance expert. Even if you have the performance expert, he can’t be expected to micro-optimize and benchmark every method.

Finally, with the JS++ Standard Library, we can fully avoid the NPM left-pad debacle.

import System;

Console.log("1".padLeft(4, "0")); // "0001"

fromString

Previously, to convert a string to number in JS++, it was a little unintuitive. For example:

int x = +"1000"; // use the unary + operator

For all numeric types, we’ve introduced the fromString, fromStringOr, and fromStringOrThrow static methods. The above example can be re-written to use Integer32.fromString:

int x = Integer32.fromString("1000");

Advanced Generics

JS++ 0.8.4 introduces covariant and contravariant generic types (including upcasting and downcasting for types with variants). Covariance and contravariance are based on use-site variance. At this time, we are not introducing declaration-site variance at all; we have higher priorities. In addition, we’ve introduced generic constraints (subtype constraints, multiple constraints, wildcard constraints, and more).

Finally, we have support for generic functions and generic static methods.

Everything from basic to advanced generic programming in JS++ is covered in our generic programming documentation.

When we released version 0.8.0, we introduced only basic generics. In today’s 0.8.4 release, you can consider generics fully implemented.

I highly encourage reading the generic programming documentation. To put it all together, here’s generic covariance and contravariance together with use-site variance:

import System;
 
abstract class Animal {}
class Tiger : Animal {}
 
abstract class Pet : Animal {}
class Dog : Pet {}
class Cat : Pet {}
 
class PetCollection
{
    Pet[] data = [];
 
    void insert(descend Pet[] pets) {
        foreach(Pet pet in pets) {
            this.data.push(pet);
        }
    }
 
    ascend Pet[] get() {
        return this.data;
    }
}
 
auto myPets = new PetCollection();
 
// Write operations (descend, covariance)
myPets.insert([ new Dog, new Cat ]);
// myPets.insert([ new Tiger ]); // not allowed
 
// Read operations (ascend, contravariance)
Pet[] getPets = [];
Animal[] getAnimals = [];
ascend Pet[] tmp = myPets.get(); // read here
foreach(Pet pet in tmp) { // but we still need to put them back into our "result" arrays
    getPets.push(pet);
    getAnimals.push(pet);
}
 
// Now we can modify the arrays we read into above
getPets.push(new Dog);
getAnimals.push(new Dog);
getAnimals.push(new Tiger);
// getPets.push(new Tiger); // ERROR

Other Changes

  • Fix return types for System.String.charAt and System.String.charCodeAt
  • Fix type promotion to ‘double’. We now handle this better than languages like Java and C#. Thanks to our lead engineer, Anton, for the idea.
  • isEven() and isOdd(). You might think this is fizz buzz, but if you’re using the modulus operator, it’ll be slower. We use bitwise operations, and you might be interested in reading this article on how we took advantage of overflow behavior to improve performance while preserving correctness.
  • Fix System.Array.map and System.Array.reduce to support wildcard generic types.
  • Type inference of generic parameters for function calls. This is needed for System.Array.map and System.Array.reduce, but it’s also available for user-side code.
  • Fix System.Console.error when no console is available
  • Fixed error message with incorrect type for setters defined with no accompanying getters.
  • Fixed private access modifier for modules in a multi-file setting.
  • Fix callback types as generic arguments
  • Fix enum bitwise operations to reduce explicit casting

Leveraging Integer Overflow to Improve Performance While Preserving Correctness

If you use the upcoming UInteger32.isEven or isOdd methods, you’ll notice that it uses a bitwise AND operation. The reason, as described in a previous post, is because it improves performance.

However, while this is straightforward for all other integer wrapper classes, UInteger32 is an exception. According to ECMAScript 3 11.10:

The production A : A @B, where @ is one of the bitwise operators in the productions above, is evaluated as follows:

  1. Evaluate A.
  2. Call GetValue(Result(1)).
  3. Evaluate B.
  4. Call GetValue(Result(3)).
  5. Call ToInt32(Result(2)).
  6. Call ToInt32(Result(4)).
  7. Apply the bitwise operator @ to Result(5) and Result(6). The result is a signed 32 bit integer.
  8. Return Result(7).

The operands (and, thus, the result type) for the bitwise AND operation in ECMAScript are converted to 32-bit signed integers. System.UInteger32 represents an unsigned 32-bit integer.

This is inconvenient because we’d obviously have to fall back to the slower modulus operation for isEven/isOdd on UInteger32. Unless…

((Math.pow(2, 32) + 1) >>> 0 | 0) & 1 // true
((Math.pow(2, 32) + 2) >>> 0 | 0) & 1 // false

We can take advantage of overflow behavior. (Note: since we’re able to get the correct result by leveraging overflow behavior, we actually don’t perform the extraneous zero-fill right shift as illustrated in the example.)

This is completely safe because:

A) Mathematically, in base 2, the last bit will always be 1 for odd numbers and 0 for even numbers… no matter how big the number is.

B) Bitwise AND will compare both bits in equal-length binary forms. Thus, no matter how big the number is, when you AND against 1, it will always be 0000001 (or zero-padded to whatever length is needed). Therefore, all the preceding bits don’t matter, because they will always be ANDed against a zero bit. The only bit that matters is the trailing bit, see A for why this will always work.

Standard Library Performance: isEven() and isOdd()

Remember what I always advise: always use the JS++ Standard Library if you can. The methods aren’t just well-tested for validity, but we also test for performance.

Checking if a number is even or odd is the classic fizzbuzz test. Most professional developers can use the modulus operator. However, that’s not always the fastest implementation.

> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i & 1) == 0; console.log(x); new Date - t;
false
87
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i & 1) == 0; console.log(x); new Date - t;
false
90
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i & 1) == 0; console.log(x); new Date - t;
false
86
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i & 1) == 0; console.log(x); new Date - t;
false
86
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i & 1) == 0; console.log(x); new Date - t;
false
86

= 87ms

> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;
false
105
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;
false
100
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;
false
100
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;
false
104
> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;
false
101

= 102ms

Node.js v8.11.1 Linux x64
Core i7-4790k, 32gb RAM
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i & 1) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
1948 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i & 1) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2072 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i & 1) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2086 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i & 1) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2092 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i & 1) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2102

= 2060ms

var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2058 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2082 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2114 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2102 debugger eval code:1:96
var t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);
false debugger eval code:1:80
2104 debugger eval code:1:96

= 2092ms

Firefox 59.0.2, Linux x64
Core i7-4790k, 32gb RAM

While the results are not statistically significant in Firefox (because it's very possible SpiderMonkey is manually optimizing this case via a pattern-matched optimization), you can get a 17% performance gain in Node.js via bitwise AND.

Due to all the layers of abstraction in JavaScript, it's not entirely evident how much faster a bitwise AND for isEven/isOdd can really be. In our benchmarks, we were able to achieve a 17% performance improvement in Node.js. As our lead engineer pointed out via email, according to this table, "for Intel Skylake-X `div` has a latency of 26 (for 32-bit integers), whereas `and` has latency 1 ("reciprocal throughput" has similar difference) so it is an order of magnitude slower, not 20% as in your tests."

Look for isEven() and isOdd() to appear in a future version of the JS++ Standard Library.

You may also be interested in reading Part II of this post which describes how we leveraged overflow behavior to improve performance while preserving correctness for UInteger32.

Google Image Search Broken with TypeErrors

First of all, this is not an April Fools joke. It’s unfortunate that Easter Sunday falls on April Fools Day.

Google Image Search isn’t working with custom image sizes on Easter Sunday. A closer inspection reveals a plethora of runtime TypeErrors:

When you click “Go” above, nothing happens. Form submissions that do nothing are a common problem with JavaScript runtime failures.

It’s important to remember, with JS++ “type guarantees,” it is possible to completely eliminate type errors via a sound type system.

Update:

This bug is still happening as of Monday, April 2. It’s happening as far as Russia. Steps to reproduce:

1. Go to google.com
2. Search “black forest”
3. Navigate to Image Search
4. Under Tools -> Size -> Exactly… Try 1920×1080.