I have been following the WebAssembly development since its initiation and given talks about it, but I haven’t really blogged anything related to it. In this post I want to share with you an idea I got some time ago about gathering all languages that can be compiled to WebAssembly. You can see the demo or browse the source.
The initial idea around WebAssembly was to allow compilation from C and C++, as there are many libraries (f.x., gaming, VR, codecs) that could be ported to the Web right away. The compilation architecture is designed to be extensible, meaning that other languages could also be compiled to WebAssembly. Indeed, other language creators (and the community behind them) started experimenting with that.
My idea with the Wheel of WebAssembly is to create a demo of each language that can be compiled to WebAssembly. As the WASM format is standardized, in theory I would expect to get “same” WASM files and to be able to load them on the Web the same way. In practice, it is not the case.
Languages
I wanted to gather all languages and show them dynamically in a wheel (like the Wheel of Fortune). Each language source shall define two functions:
- name() – returning the name of the language, and
- feelingLucky() – returning a random integer from 1 to 100.
As I said earlier, I would expect each language source to lead to the same WASM output. Then I could load each WASM the following way:
1 2 3 4 5 6 7 |
fetch('wheel-part-lang.wasm') .then(response => response.arrayBuffer()) .then(bytes => WebAssembly.instantiate(bytes, imports)) .then(({ module, instance }) => { const name = readStringFromMemory(instance.exports.name()); const lucky = instance.exports.feelingLucky(); }); |
There are a few challenges at this point:
- WebAssembly supports only numbers. Strings are written on the linear memory and can be read from JavaScript afterwards. However, different compiler write strings in different ways. C and C++, for example, use zero-terminated strings, meaning a sequence of characters followed by a zero. AssemblyScript, the compiler for TypeScript, uses a special decoding scheme for strings.
- Generating a random number is not supported by all languages or not possible to compile it (easily) to WebAssembly. That is why some languages rely on (import) JavaScript’s Math.random() for generating a random number.
- In order to run C# in the browser, one would need a .NET runtime. Mono has examples of compiling C# to native, plus CoreRT project works in the same direction, however both are still experimental and require a more difficult set-up. That is why I decided to create a special WASM loader using DotNetAnywhere – a simple .NET runtime ported by Steve Sanderson.
Compilation
As there are many language sources, my ambition was to be able to compile each language using a NPM package. Unfortunately, not every language exposes its compiler as a NPM package (or the existing NPM packages are not maintained), so compiling each language source requires a specific set-up. Then I use Node’s child process execution to trigger the compilation.
Next steps
My plan is to update the source with more languages when I see they get support for WebAssembly. You are more than welcome to send me a pull request, as well, or open an issue to discuss different parts of the demo.