Meet AssemblyScript: your next computing language
Note: AssemblyScript SDK (@fastly/as-compute) for Fastly Compute@Edge has been deprecated in favor of the more up-to-date and feature-rich JavaScript SDK (@fastly/js-compute).
Hello! I’m Aaron Turner, a senior software engineer on our Compute@Edge serverless compute environment, as well as a member of the AssemblyScript core team. We announced in our latest update to Compute@Edge that we’re supporting AssemblyScript — today, let’s take a deep dive into that fairly new language. Though it’s a bit ironic, I think the best way to start this discussion is with another language — JavaScript.
JavaScript is one of the most widely used programming languages. But it’s not always a perfect fit — like when you’re running logic at the edge. Downsides mostly revolve around JavaScript being a dynamically typed, interpreted language, meaning it requires a runtime to execute.
JavaScript runtimes must be heavily optimized and use techniques like Just-in-Time compilation to get JavaScript to perform at a level close to statically typed compiled languages in a best-case scenario at runtime. Runtimes like V8 do an amazing job at executing JavaScript using a reasonable amount of resources, but it would be more performant to not use a language that is dynamically typed or interpreted. What if we could have a similar developer experience to JavaScript but with the benefits of a statically typed compiled language?
TypeScript provides part of the answer by adding types to JavaScript, thereby, introducing type-safety to JavaScript applications. TypeScript is widely used among JavaScript developers: ~80% of JavaScript developers use, or want to learn, TypeScript. However, TypeScript doesn’t go the full distance toward compiled languages: it type-checks code but ultimately strips the types away to produce pure JavaScript rather than a fully-compiled binary.
Enter AssemblyScript
AssemblyScript is a variant of TypeScript that produces WebAssembly binaries, the binary format that powers Fastly’s Compute@Edge. WebAssembly is a new technology that is supported by all major browsers. Relative to JavaScript, WebAssembly offers predictable performance, making WebAssembly well suited for computationally intensive tasks. WebAssembly is also very portable, as it can be easily distributed in package registries like npm, and run in both the browser and standalone runtimes like Lucet.
While AssemblyScript requires stricter typing than TypeScript does, it sticks as close as possible to TypeScript syntax and semantics — which means that most JavaScript developers will find AssemblyScript comfortable to use — and it enables great support for the modern JavaScript ecosystem. For instance, the AssemblyScript compiler is available on npm, as well as common AssemblyScript tools and libraries like as-pect. AssemblyScript files also use TypeScript’s `.ts` file extension, and it includes proper typings for allowing AssemblyScript to piggy-back on TypeScript tooling, such as the TypeScript linter. With the right small tweaks, AssemblyScript can even be used with the TypeScript compiler.
This is very exciting, as AssemblyScript offers a low-overhead entry-point for JavaScript developers to pick up a language to output WebAssembly — both in terms of learning to read and write AssemblyScript, as well as using a lot of the pre-existing tooling that may already be in a JavaScript developer’s workflow. AssemblyScript is often referred to in the WebAssembly community as a great gateway to picking up WebAssembly. It offers a large group of developers who already write applications for the web a path to pick up and learn WebAssembly. Even if you are starting from scratch and are not particularly familiar with JavaScript or TypeScript, AssemblyScript is a solid choice when picking a language to start outputting WebAssembly.
However, as things stand today, AssemblyScript does have some shortcomings that should be considered.
Growing pains of AssemblyScript in 2020
AssemblyScript is a very new language and, as such, has some maturity issues. For example, two commonplace language features missing from AssemblyScript are support for Closures and Regex. The lack of closures makes it difficult to pass functions to other functions (a common practice in JavaScript and TypeScript). The lack of regex makes it difficult to parse and modify strings, which is critical for some applications. Thankfully, both of these language features are in development for AssemblyScript.
Additionally, because AssemblyScript language is still young, its community and ecosystem are young as well. As the community grows, it should be more commonplace to see ports of common JavaScript and TypeScript libraries to AssemblyScript. These ports could then be shared on commonplace JavaScript package registries like npm. Also, we are already seeing very impressive alternative solutions to common JavaScript libraries for AssemblyScript. For example, `as-pect` is a unit testing framework for AssemblyScript, that takes a lot of notes from Jest. `as-wasi` is a high-level library on top of WASI (the WebAssembly System Interface) for interacting with system resources (FileSystem, Time, etc.) like the Node API.
Is AssemblyScript right for you?
First, I’d like to address what I think AssemblyScript should not be used for. As we mentioned a couple of times in this article, AssemblyScript is not a replacement for your current JavaScript or TypeScript applications. You should not expect to be able to take your `ts-node` app, or a snippet of JavaScript that relies on common globals in the browser (like `window`), and just be able to run it through the AssemblyScript compiler to get WebAssembly “for free.”
What AssemblyScript provides is a great stepping stone, with a very small learning curve, for porting your existing JavaScript or TypeScript code, and its JavaScript or TypeScript dependencies, to WebAssembly. Because your new AssemblyScript application and ported dependencies (if no alternative dependencies already exist), can be compiled to WebAssembly through the AssemblyScript compiler. If your application or library does not depend on any platform globals (or in other words, your JavaScript or TypeScript is ‘Isomorphic’ or ‘universal’), then porting could be as simple as adding or changing a few types of your code. If your project or its dependencies use platform-specific globals, this becomes more difficult, as you will need to re-implement these globals or import them through your host runtime. Keep an eye out for a future article on techniques for porting JavaScript applications to AssemblyScript.
If you’re starting from scratch, AssemblyScript is also a great language for getting started with WebAssembly. If you or your team has a JavaScript or TypeScript background, you'll have an especially easy time picking up AssemblyScript. The syntax similarities and modern JavaScript workflow make it easy to learn how to use AssemblyScript and add it to your current projects. If you aren’t already familiar with JavaScript or TypeScript, additional features of AssemblyScript also help with lowering its learning curve. For example, AssemblyScript provides low-level access and API helpers for the concepts that make up WebAssembly. Therefore, understanding how code is executed and data is passed around your application as it is executed as a WebAssembly module, should be less difficult to pick up.AssemblyScript is an exciting new language, and we look forward to seeing its community grow.
For more information, check out my talk from Web Directions Code 2020 below. We hope the language can be useful for you, Fastly, and our customers. We’ll be keeping an eye on AssemblyScript — and hope you will as well.