April 20, 2022

WebAssembly Languages

Matt Butcher Matt Butcher

grain assemblyscript webassembly

WebAssembly Languages

WebAssembly has been steadily gaining momentum over the last few years. It should come as no surprise that a batch of new programming languages are specifically targeting WebAssembly. In this article, we consider a few of those, including Grain and AssemblyScript.

AssemblyScript and Grain are both supported on the Fermyon Platform using Spin’s Wagi executor.

WebAssembly and Specific Languages

WebAssembly was originally written to make it possible to compile existing languages, like C and Rust, into a format that can be run in the web browser. Over time, though, the strengths of WebAssembly have made it a good candidate for running outside of the browser. And as a format, it has one enough influence that a handful of new languages have been built specifically for WebAssembly. (If you are interested in our perspective about WebAssembly and the cloud, read our Introduction to WebAssembly on the Cloud)

While there are a few such languages, we will focus on a pair of them in this article.

AssemblyScript

Microsoft’s TypeScript language is a more structured, type-safe version of JavaScript. TypeScript is usually converted to JavaScript before it is deployed to browsers or Node.js.

Several WebAssembly developers saw TypeScript as a starting point for a language that would compile to WebAssembly. AssemblyScript borrows much of TypeScript’s syntax and type system, but makes it slightly more rigorous. While TypeScript is converted to JavaScript, AssemblyScript is compiled to WebAssembly’s binary format.

Here is an example AssemblyScript program:

import "wasi";
import { Console } from "as-wasi";

Console.log("Hello");

This program simply writes “Hello” to the system’s STDOUT. It looks indistinguishable from TypeScript. Note that we import a couple of libraries to add WASI (WebAssembly System Interface) support to AssemblyScript. By default, AssemblyScript makes very few assumptions about the WebAssembly runtime in which it will be executed. In order to print to standard output, we have to import WASI.

For a longer example of an AssemblyScript module, take a look at an example I built for Wagi and also read the project’s language documentation.

The strong point of AssemblyScript is that you can work in a familiar syntax and build WebAssembly-specific applications. However, because of the stricter type system, you may find that many of your favorite TypeScript libraries will not work with AssemblyScript. Even with that consideration, we find AssemblyScript to be a pleasant language that turns out compact WebAssembly binaries.

One major difference between AssemblyScript and TypeScript is that AssemblyScript always requires an explicit data type, and does not allow use of the any, undefined, or union types – all features that TypeScript supports. This can initially be confusing for seasoned TypeScript developers.

Installing AssemblyScript should feel comfortable and familiar to anyone who has done Node.js programming in the past. Using npm, you can install AssemblyScript as a pair of packages:

$ npm install --save @assemblyscript/loader
$ npm install --save-dev assemblyscript

From there, follow the official instructions to initialize a new project. Because AssemblyScript uses Node.js in its toolchain, it sets up a special directory structure that includes the familiar package.json but stores all of the source code in an assembly/ subfolder.

AssemblyScript runs great in Spin using the Wagi executor.

Grain

While AssemblyScript is an object oriented language, Grain is a functional programming language. Boasting a strong standard library that is tailored to WebAssembly’s current feature set, Grain is a delightful language for writing WebAssembly tools.

Here is a simple program written in Grain that uses WASI support to print out environment variables defined for the processes:

import Process from "sys/process"
import Array from "array"

print("==== Environment: ====")
Array.forEach( print, Process.env() )

The above is part of an example Grain program for Wagi or Spin. We have also written a Wagi/Spin file server in Grain, which provides a richer example of how to write real Grain programs.

One of Grain’s strong points is its excellent documentation. Within minutes, you can get up and coding with Grain’s local development toolkit.

Being a functional programming language, Grain is primarily oriented around functions which can be collected into packages. For example, all of the built-in functions for manipulating strings are available in the String package. Packages bundled into the Sys/ namespace (Sys/File, Sys/Process, etc.) make use of WASI. Most of the non-Sys/ packages will work even on non-WASI runtimes (like the browser).

One of our favorite features of Grain is its support for match, Option, and Result in a very Rust-like way. For example, a function that may experience an error returns a Result object wrapping a good value (on success) or an error value (on failure). Using a match statement, developers can then handle either case:

match (Random.random()) {
    Ok(number) => print("I got a number from the random number generator"),
    Err(e) => print("Something went wrong when generating a random number")
}

Installing Grain is straightforward. On a Mac, you can install from Homebrew. Linux and Windows binaries can be fetched from the links in the documentation. While it takes a few minutes to compile the system library the first time, thereafter it is a quick process.

You can write Spin apps in Grain by using the Wagi executor.

Conclusion

Grain and AssemblyScript are just a few of the new WebAssembly oriented languages. And we foresee more on the horizon. But this pair of languages shows the breadth of options. AssemblyScript is an object-oriented language inspired by TypeScript and JavaScript. Grain is a functional programming language with roots in languages like Haskell, Rust, and OCaml (among many others). We have found both to be usable and useful, and both produce small WebAssembly binaries that run quickly.

If you are interested in other programming languages in the WebAssembly ecosystem, check out our language matrix, which covers everything from AssemblyScript to Zig (including C, Python, Ruby, and Javascript).


🔥 Recommended Posts


Quickstart Your Serveless Apps with Spin

Get Started