Classes in AssemblyScript

Overview

Like TypeScript, AssemblyScript offers several OOP features such as classes and
inheritance. You can create classes in AssemblyScript, and then use tools such as asbind, or the AssemblyScript loader to access those classes from JavaScript. In this
tutorial, I am going to walk you through creating a class and subclass in AssemblyScript
and then using as-bind to create objects from those classes within JavaScript. The first
thing we should do is install the as-bind module using npm:

npm install --save as-bind

Later in this tutorial, we will need to include the as-bind library when we compile our WebAssembly
module. Let’s create a class called Vector2D, which is a vector in 2D space with a
directional x and y component. We will then create a second class called Vector3D that
extends Vector2D adding a z and w component. Create a file called ASBindTest.ts and
add the following code:

// Vector2D is a mathematical vector in 2D space.// It has an x and y directional component and a magnitudeexportclass Vector2D {
// x and y directional component of the vector
x: i32;
y: i32;
// constructor for initializing the x and y componentsconstructor(x: i32, y: i32) {
this.x = x;
this.y = y;
}
// the squared magnitude of the vector
MagSQ(): i32 {
returnthis.x * this.x + this.y * this.y;
}
// getting the magnitude of the vector
Magnitude(): f32 {
return f32.sqrt(<f32>this.MagSQ());
}
}
exportclass Vector3D extends Vector2D {
// This adds a z attribute to the x and y attributes inherited from Vector2D
z: i32;
// I know It’s not technically a 3D vector if it has a w component :-p// I have this w component as a private attribute to demonstrate that// it will not be exportedprivate w: i32;
constructor(x: i32, y: i32, z: i32) {
super(x, y); // calls the original constructorthis.z = z;
this.w = 0;
}
// This calls the Vector2D MagSQ function and adds the z component
MagSQ(): i32 {
returnsuper.MagSQ() + this.z * this.z;
}
// Adding the Magnitude method to Vector3D would be unnecessary in TypeScript// AssemblyScript has no virtual function lookups, so Magnitude must be// overridden with the exact same code. Otherwise MagSQ would be called// on the Vector2D class instead of the Vector3D class.
Magnitude(): f32 {
return f32.sqrt(<f32>this.MagSQ());
}
}
// I’m creating this Vector3D object to show that private variables in// AssemblyScript are not so private. AssemblyScript does not yet enforce// access level modifiers like public, private and protected.let v = new Vector3D(3, 4, 5);
// even though w is private, AssemblyScript does not prevent you from updating
v.w = 1;

As you can see, there are currently some limitations to OOP within AssemblyScript. Many
of these limitations are because several language features are still under construction.
Classes in AssemblyScript can not yet implement an interface. AssemblyScript does not
enforce access level modifiers such as public, private, and protected. The private
keyword does prevent a public class from exporting the attribute or method to JavaScript,
but that is all. Now that we have our AssemblyScript written, we need to compile it into a
WASM module. To use as-bind, we have to include the as-bind library that we installed
using npm. Use this asc command to compile the WASM module:

Compiling our code with the as-bind.ts file simplifies what we must do from our JavaScript.
I will be using Node.js to run the JavaScript that calls into our WebAssembly module.
Create a file called ASBindTest.js and add the following code:

When using the as-bind module to instantiate a WebAssembly module, it places the
classes we exported from that module in the unboundExports object inside. In the code
above, I used the destructuring syntax to pull them into class constructor variables. You
can run ASBindTest.js using node with the following command:

Notice the line w: undefined in the console output. The w attribute is undefined
because we used the private keyword when we created that attribute in the Vector3D
class. If we remove the Magnitude function override from our Vector3D class in the
AssemblyScript and recompile, we would see both magnitude lines in our console reading
Magnitude: 5 instead of the second one reading Magnitude: 7.071067810058594.
That is because AssemblyScript has not yet implemented a method for looking up function
overrides. The Magnitude function does not know that it should be calling the MagSQ
function for the Vector3D class and not the Vector2D class.