Back to blog

Follow and Subscribe

Evaluating new languages for Compute

Aaron Turner

Senior Engineer, Fastly

When we announced the beta for Compute we told you our focus would be on Rust as the first supported programming language. And while it's a great place to start, it's really just the beginning. We know how important developer ergonomics are, so our vision for Compute includes making sure you can use the programming language you prefer. (If you're curious about that, check out Terrarium, one of our first experiments exploring WebAssembly at the edge). 

We recently surveyed Compute beta participants about which languages they'd like to see supported, and while a few favorites rose to the top, there was interest in support for nearly 20 different languages. In order to get there, we are using a disciplined and programmatic approach. We look at everything from features, tooling, and ecosystem to performance and WebAssembly support. Each language comes with its own set of challenges to resolve, but the evaluation process is pretty interesting. And we want to share more of our thinking on that with you here.

Criteria for a language to be supported by Compute

The first step in this process is to define what requirements are necessary for a language to be supported by Compute. Defining this allows us to build criteria that we can then evaluate a language against. These are our criteria:

Language features

The considered language should have features that its intended target audience of developers are comfortable with.

Language tooling

The language should have tooling for building and managing projects. That tooling includes testing solutions, project generation, and code linting.

Language ecosystem

The language should have a friendly, welcoming community ecosystem. Community members should be able to build and share libraries, documentation, and additional tooling.

Performance

The language should have a runtime that starts quickly and runs reasonably well.

WebAssembly support

To power Compute we use Lucet, our open-source WebAssembly runtime and compiler which, naturally, runs WebAssembly modules. Therefore, it is preferable that the language should be able to compile to WebAssembly, and be able to adapt its other qualities to WebAssembly as well. We’ll get into this later, but preferable doesn’t mean it’s essential.

Looking at these criteria, you might be starting to see why we chose Rust as Compute’s first language. Rust is a mature language with a great standard library. It has Cargo, which offers a great way to manage Rust projects and use libraries and tooling from the community. The Rust Book(s), and Docs.rs are popular documentation resources. Crates.io is a popular resource for finding and distributing re-usable Rust modules. Rust has great all-around runtime performance. Lastly, Rust has one of the best toolchains and ecosystems for WebAssembly and WebAssembly is among the language’s core focuses.

As I mentioned, just because a language does not compile to WebAssembly, doesn’t mean it can’t be considered. It just makes things more complicated. WebAssembly itself is still young and evolving, so there are many great language features that don’t quite translate. Since threads are a relatively new feature of WebAssembly, languages that depend on threads would probably have a hard time making the transition. Interface Types and Garbage Collection are open proposals for WebAssembly, which make it difficult to compile dynamically typed languages with a runtime to WebAssembly in its current state. But we’ve got ideas on how to make it work, which I’ll get into later in the post.

Now that we have these criteria defined, let’s explore some of the languages we’re considering and how these criteria apply. These languages are AssemblyScript and Go.

AssemblyScript

JavaScript is the most popular programming language. It is also the most commonly requested language from our customers that are interested in Compute — and has been requested by a whopping 82% of our surveyed beta participants. However, JavaScript cannot compile to WebAssembly. Currently, WebAssembly requires strict typing and does not provide a garbage collector; JavaScript is incompatible with both of these features. To close this gap, we’ve been exploring solutions to allow JavaScript developers to comfortably write WebAssembly modules.

The language we currently see as a solution is AssemblyScript. AssemblyScript is a strict subset of TypeScript, where TypeScript is a typed superset of JavaScript. TypeScript is quite popular in the JavaScript community. Over half of JavaScript developers have used TypeScript and plan to continue using it for future projects. It also has its own optional runtime for handling memory management and garbage collection.

AssemblyScript is not a solution for compiling your node-ts application, or TypeScript React app to WebAssembly. However, AssemblyScript is a solution to write small and fast WebAssembly modules using tooling that JavaScript developers are comfortable with. Some of these tools include npm, TypeScript linters, and JavaScript bundlers. AssemblyScript is already being used in production by several projects, or being explored as a production-ready language, by the industry.

So how does AssemblyScript fit into our defined criteria? It definitely satisfies our performance requirements and language tooling. The language is using tooling already available in the modern JavaScript workflow, which is a huge win when considering the language for Compute. However, there are a few items we are taking into consideration. AssemblyScript is still a bit of a young language and is missing some features that we think JavaScript developers will expect, such as closures. Also, AssemblyScript cannot use any existing JavaScript or TypeScript libraries, therefore it cannot tap into the modules that are already present on npm. There are some really interesting community libraries and tools that exist for the language such as: as-pect, as-bind, and as-wasi. However, we don’t currently see a large amount of community libraries and tooling that could help drive applications written in AssemblyScript.

AssemblyScript is a language that we are extremely excited about. In fact, Fastly has been a sponsor to AssemblyScript’s OpenCollective since March, 2019. We are really excited to see how AssemblyScript evolves.

Go

Go is another popular language that is often requested by our customers. Go is an open source, general purpose programming language and is widely used in large scale production applications. It also meets a lot of our defined criteria. It’s a mature language with extensive language features. It has great tooling through its CLI and a great standard library. It has a large ecosystem for sharing and using modules through `go get` and has amazing performance in most cases. Lastly, Go supports compiling to WebAssembly! However, there are some challenges. WebAssembly support in Go is still very young and has some sharp edges. Go WebAssembly often produces very large WebAssembly binaries. The performance of Go WebAssembly modules tend to be a bit slower relative to other solutions for writing WebAssembly modules. Go WebAssembly does have good community documentation when targeting the web with Go WebAssembly, however stable support for compiling to the WebAssembly System Interface (WASI)  is still an open issue as of April, 2020.

One solution for addressing some of the performance implications of Go WebAssembly, is to use TinyGo. TinyGo is a compiler for Go, that focuses on bringing Go to “small places”, such as microcontrollers. It also compiles Go to WebAssembly and produces much smaller WebAssembly binaries. TinyGo is a young project as well, therefore community support is still growing and resources for WASI are still a bit immature.

We are really excited to see how Go’s WebAssembly support evolves, especially in the areas of WebAssembly performance and community support for WebAssembly and WASI. 

Languages that don’t compile to WebAssembly

One last thing we’d like to discuss is a language’s ability, or lack thereof, to compile to WebAssembly. AssemblyScript and Go are both languages that compile to WebAssembly, but there are languages we would like to support that do not. You may be wondering, if the language does not compile to WebAssembly, how would it run on Lucet? Well instead of compiling the program itself to WebAssembly, we could compile the language’s runtime to WebAssembly.

For example, Lua, PHP, and JavaScript already have runtimes that compile down to WebAssembly. In fact, we’ve been playing around with an experiment of running a WASI compiled QuickJS on Lucet, and are taking a look at some of the performance and ecosystem implications of supporting JavaScript directly on Compute.

Taking a look at our criteria for a language, compiling a language’s runtime to WebAssembly really helps to check a lot of the boxes. Ideally, having a language’s runtime compiled to WebAssembly means we get to use all of the language’s features and tooling for free! However, depending on the language, the language’s ecosystem may or may not work with alternative language runtimes out-of-the-box. Our biggest concern with this solution is that there would be a performance overhead problem. Compiling the language runtime would increase startup time as the runtime bootstraps itself, and depending on the runtime, it may have a slower runtime performance compared to more popular runtimes.

What comes next

As you can see, there’s a lot that goes into evaluating which programming languages Compute will support. Beyond evaluating and monitoring the evolution of these programming languages, and several others, we’re also actively investing in their ecosystems where we can. If you’d like to join our efforts, projects like wasmtime, proxy-wasm, wasi, and AssemblyScript could all use your support. And be sure to sign up for the Compute beta if you’re not already on the list. We’re looking forward to sharing more with you soon. Until then, we’ll be working on ways to help you build the things you love, with the tools you love!