Evaluating new languages for Compute@Edge
When we announced the beta for Compute@Edge, 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@Edge 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@Edge 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@Edge
The first step in this process is to define what requirements are necessary for a language to be supported by Compute@Edge. Defining this allows us to build criteria that we can then evaluate a language against. These are our criteria:
The considered language should have features that its intended target audience of developers are comfortable with.
The language should have tooling for building and managing projects. That tooling includes testing solutions, project generation, and code linting.
The language should have a friendly, welcoming community ecosystem. Community members should be able to build and share libraries, documentation, and additional tooling.
The language should have a runtime that starts quickly and runs reasonably well.
To power Compute@Edge 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@Edge’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 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 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.
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@Edge 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@Edge 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!