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.

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++.