Hands-on WebAssembly
evilmartians.com
evilmartians.com
I have done a number of experiments with Go’s WASM target, one of the earliest and silliest porting Go’s “Otto” JavaScript runtime to WASM, so you can much less efficiently run ES3 JavaScript in a browser.
I have also been working on porting a number of tools I currently have that run server side with web frontends to pure WASM. I have had mixed success here however and have found interacting with web elements and JavaScript from Go an awkward, non statically validated, frustrating experience of trial-and-error that somewhat undermines the joy of a statically typed language. On top of everything, Go’s .wasm files are frustratingly large, “Hello World” starting at 1mb and growing quickly from there.
All that said though, it is pretty magical seeing something written as a CLI tool running in a browser with minimal changes.
For me Rust offers the best WASM experience and tooling at the moment.
Rust has no GC and (almost) no runtime.
It also has official wasm build target support out of the box, including generating Typescript definitions for Rust types.
The ecosystem is somewhat well-developed:
* wasm-bindgen for general interop in both directions
* js-sys / web-sys for (low-level) type-safe and surprisingly efficient browser API bindings
* wasm-bindgen-futures for easy Promise <-> Future interop
* wasm-pack for easy building
* ...
Getting the code size low is still a challenge though.
A Rust implementation of the Krausest frontend framework benchmark takes a top 4 spot [1]. Despite this benchmark not favouring wasm at all since it requires little computation and mostly does FFI calls.
(ps: C++ is in a decent state as well)
[1] https://rawgit.com/krausest/js-framework-benchmark/master/we...
I’d still choose Go or Rust over C++, though, because they’re memory-safe. This recent discussion shows that’s still important in the context of WebAssembly: https://news.ycombinator.com/item?id=24216764
But a huge amount of the worlds software is written in C++, and will remain so for decades.
Getting some of that code to run well in WASM can be a big win for certain domains.
I expect that WASM doesn't have the concurrency model required by a modern concurrent garbage collector like Go's, but perhaps I'm wrong.
Years ago, I wanted to write some code that could run both as part of a command-line app and an in-browser tool. I asked what language I should use for this shared code and was told, basically, that there was no suitable language.
Now, thanks to WASM, there are lots!
Tools like GopherJS, Elm, Dart and such output JavaScript no human could reasonably interpret. WASM seems logical for them. TypeScript outputs very human readable JS (for the most part) and WASM seems to have little virtue.
As someone who learned JavaScript in the late 90s / early 2000s reading websites code, outputting readable JS feels like giving back.
This has been true for years, various languages can compile down to JavaScript. Kotlin and Dart, for instance.
Also, doesn't WASM lack a garbage collector? I imagine porting a language to WASM is still quite a task, and presumably a GC written in WASM is going to be far inferior to one provided by the browser, as with JavaScript. (Corrections welcome if I'm wrong about that.) That's not to dismiss the potential for performance gains in situations well suited to WASM.
(I see the_duke already mentioned the GC situation.)
That's because officially Go has not support for web APIs(as wasm has no access to web apis) so you have to callback through JavaScript. However once you build the right wrappers around JS APIs and the tools to deal with HTML the experience is pretty nice.
You can also see this with Gio UI library in Go where they try to minimize GC overhead yet one keeps hitting GC pauses in WASM. The author talks about some of the issues with Go on WASM here: https://changelog.com/gotime/128
It did help that after diving back into the new stuff in 'modern C++' with auto, lambdas and move semantics I was able to write quite ergonomic code without any actual manual memory management stuff going on.
The intention is likely that if the onboard computer emulation crashes (which it sometimes does) you can simulate the actual onboard computer restarting without it taking down the game.
That doesn't really make any sense to me as a motivation. The vast majority of ways they could have chosen to simulate the onboard computer would have that quality. I would guess they chose WASM because they expect a lot of third-party expansion and it provides a VM that can be targeted by almost any language.
And I would point out I've gotten the OBC in the default plane models to crash a few times, they either get stuck in some undefined state or go black and recover after a few seconds. It's rather interesting to observe.
The WASM Runtime used is on github, https://innative.dev/
WASMtime means you can run webassembly data on the fly from memory.
Innative compiles everything into a proper linkable C object, so you can link it as if it was natively compiled. It embeds LLVM so it should get decent performance out of everything.
The intention is likely that they use V8 isolates instead of VMs which support WebAssembly.
[1] https://blog.cloudflare.com/introducing-wrangler-cli/
SCNR :D
For example, last week me and a few other users on Observable have been experimenting with various JS ports of one particular permuted congruential random number generator. Using assemblyscript I managed to write a decent-enough WASM version, and it's slower than implementing 64 bit arithmetic with four 32 bit numbers, which involves a lot more multiplications and additions:
https://observablehq.com/d/ce811886e1071d69
There are two possible explanations: either 64 bit integer arithmetic is still really slow in WASM, or the call overhead is really, really significant.
This fits my earlier experience with trying to implement fast log approximation functions for data-viz purposes (since the rounding errors would not be visible at sub-pixel levels). They weren't much faster than the proper Math.log function (whereas in pure C or C++ that difference would be much larger).
I suspect that if this call overhead were reduced, it would be much easier to gradually add more WASM to a Web App and reap the benefits of it.
Calling overhead between WASM and JS is significant though, but it has already been optimized massively [1], I doubt that this can be improved much further). Calling a very small function across language borders is amost always a bad idea, not just in the specific JS=>WASM context.
[1] https://hacks.mozilla.org/2018/10/calls-between-javascript-a...
PS: also contrary to popular belief, JS and WASM have similar performance for simple number crunching tasks because in that situation JS is pretty fast, Javascript only becomes slow when objects and properties come into play.
> There’s only one case where an optimized call from JavaScript » WebAssembly is not faster than JavaScript » JavaScript. That is when JavaScript has in-lined a function.
Combined with your remark that 64 bit arithmetic is fast, I'd say this pretty much confirms the suspicion that a lack of inlining is what makes this particular WASM function execute slower
For what it's worth, (scalar) numerical operations in JS are actually quite close to C. It's not like python.
The problem with writing the loop on the WASM side is that passing the data back and forth between JS and WASM involves typed arrays and array buffers. That has significant overhead of its own. Still, good suggestion, I should try that with a pixel buffer!
> For what it's worth, (scalar) numerical operations in JS are actually quite close to C. It's not like python.
Indeed, and I am generally very impressed and happy with the performance of JavaScript these days! In my experience it only takes a little bit of effort to hint at the compiler if we're working with doubles or 32 bit integers, and then it goes really fast. In this particular case however we needed 64 bit integer arithmetic, so that's a bit of an edge-case.
``` const eps: f64 = 2.3283064365386963e-10; const m: u64 = 6364136223846793005; const inc: u64 = 1442695040888963407;
let state: u64 = 1;
export function random(): f64 { let oldstate = state * 6364136223846793005 + 1442695040888963407; state = oldstate; const xorshifted = u32(((oldstate >>> 18) ^ oldstate) >> 27); const out_int = rotr(xorshifted, u32(oldstate >> 59)); return eps * out_int; } ```
I recommend return f64 instead f32. This has slightly faster interop
(also, as you might have noticed, HN doesn't support MD proper. To get code blocks you have to indent it with four spaces)
const eps: f64 = 2.3283064365386963e-10;
const m: u64 = 6364136223846793005;
const inc: u64 = 1442695040888963407;
let state: u64 = 1;
export function random(): f64 {
let oldstate = state * 6364136223846793005 + 1442695040888963407;
state = oldstate;
const xorshifted = u32(((oldstate >>> 18) ^ oldstate) >> 27);
const out_int = rotr(xorshifted, u32(oldstate >> 59));
return eps * out_int;
}I'll keep that in mind in next time. Thanks for the tip!
WASM shines for numeric computation like encoding, decoding, encryption.
In the benchmarks I've seen, image encoding is 10-20X faster in WASM. Crypto is about the same speed as WebCrypto which isn't available in all browsers and runs native code.
There's an unmistakable performance advantage for compute heavy workloads.
I think it's inevitable for WASM to replace JS eventually. We're just in the early days.
WASM has 2-5X performance advantage for "most" workloads. It also parses much faster and is more compact than minified JS. Eventually the performance advantages will be too large to ignore
Do you think front-end developers will start writing C/C++/Rust instead of JavaScript? Or do we need other languages that can compile to WASM before it can replace JS?
JS isn't a great language, it's only popular because you can't use anything else on the web. The massive popularity of Typescript, even though it's only syntax sugar on top of JS, shows that the language leaves a lot to be desired.
It doesn't support threading, doesn't compile, has garbage standard library. And it's slower and more memory hungry than languages with these features like C# and Java.
There's talk of adding a "universal" GC to WASM. When this happens you'll see "traditional" enterprise languages invade enmasse
Mostly unrelated to JavaScript, there's also an effort called JWebAssembly which strives to translate JVM bytecode to WASM's binary (.wasm) or textual (.wat) format. So WASM apps could be written fine in Scala, Clojure, Kotlin, JRuby, or any other JVM language.
I think where WASM definitely replaces JavaScript is distribution over the net to browsers for heavy web applications and in Node apps. It's just way more efficient. JS might still have a place for a little bit or bauble on some sites that are mostly static HTML, but things that use huge stacks of JS libraries will have those precompiled to WASM for distribution.
Not 100% sure if that's possible with WASM runtimes now or if it's faster (IPC can be quite fast) but that's my hope.
- Typescript is an excellent language.
- Performance of Javascript is for 99% of all the websites more than good enough.
- New frameworks like Svelte are much more mobile friendly in terms of computational overhead or time to first render.
Also, work on WA has pretty much stalled.
The right frame is wherever you can benefit from running a piece of potentially untrusted code within a sandbox. This is important for platform vendors who have to run cuatomer code that they can't trust. It is also important to run what would otherwise be unsafe code in the browser (ex: I use it for audio encoding/decoding and processing). It can serve as a "plugin" mechanism for host applications that need high performance for the plugins along with safety (ex: image proc, NN models). Environments where you need extreme granular control over what's permitted for the module (hence WASI and CloudABI).
Then you can compile stuff like Java or C# to it, but end up with huge runtime bundles. But you get much of the C# behavior from TypeScript without the huge runtime, because it compiles directly to JavaScript.
If you don’t like JavaScript, like get over yourself already. Enough is enough.
It’s a a simple language, you will still have to deal with browser apis and UI development patterns no matter what language you pick, and no, type checking isn’t going to magically solve your shitty UI codebase.
WebAssembly is going to be the new Tensorflow on people’s LinkedIn unfortunately, a small word to signal ‘hey, I’m more than just a web developer’.
Unless you are compiling a video encoder or a video game, like please, just give a rest. Solve the fact that your simple app is more than 3-4 files and over abstracted first.
I'm not going to rewrite my hobby projects in JavaScript.
I can have all my plugins back, and this time there is no turning back or someone claiming how insecure it is, despite lack of bounds checking inside linear memory segments.
Mind you - I'm hopeful these can be overcome with careful design of the surrounding application - I'm currently looking at using webasm as a plugin extension mechanism for an application.
For example, I'd really like to see interactive Smalltalk environments like Pharo be available as WASM websites instead of a separate VM. They already implement their own rendering stack within a Window, so they could switch to WebGL/Canvas and not have to even interact with the DOM directly. (That may not be the best long-term solution, I don't know enough to decide, but it is definitely a good short term solution than not doing it at all).
The current state of WebAssembly is an MVP as a compilation target for a C/C++. There's still a long road ahead [1] and various browsers are in various stages along that road.
And yup. It has nothing to do with UI. That one you'll have to solve that yourself, regardless. And it doesn't help that WASM is its own sandbox with a tiny little window into the rest of the browser.
WASM is definitely suited for some applications (see Figma), but you have to have a use case for it, and prepared to work really hard to make it work for you (once again, see Figma). Just compiling something down to it and pretending that's it, well, isn't it. And the vast majority of examples and experiments with WASM are just that: "let's compile something to WASM, yay, awesome".
You will still have take time and think through your app flows, your async user interactivity, your transitions, state, templates, etc, no matter what language you pick.
Type checking, compiling, the greatest language, will not solve the hard problems for you.
Your all pissed UI development isn’t a ‘if I know backend, then I must surely know frontend, and if I don’t, then surely somethings wrong with frontend’.
Nope. Trust me, I know a thing or two about deferred anger, I’m a serial offender when it comes to that so I can spot it easy.
I am more than happy with Forms, Qt/Qml, WPF, Android, VCL, Win32, WinUI, WebGL, GL, DirectX, LibGNM, GX,Cocoa,....
Now HTML, with <li> customized via CSS to simulate a menubar, nuke it!
Classism has no bounds.
It’s entirely possible you’ve written bad UIs with all of those technologies too you know. Afterall, no one has eeever seen a bad desktop application before.
All those compiled type safe languages with native rendering got you some amazing UIs like Microsoft Office suite for decades, right?. All those beautiful java apps for example, right? Everyone’s so full of shit. You guys couldn’t solve it with the exact technologies you are pushing for the web for literally decades.
I’m also happy you picked up on the vibes, wasn’t sure if I was being overt enough.
Classisim are Web developers that don't know any better and can only think of Web as the only way to do UIs.
Thankfully most UI/UX experts know their business to think otherwise.
WebAssembly is a done deal, all browsers support it, now we're waiting for reference types and GC, once that lands (ref types are already available in some browsers), the web will not be tied to JS in any way. I think it's fair to say that the world has moved beyond JS.
Btw I think people doing UI apps in C# (Blazor is probably second largest Wasm community after Rust) are fully aware of the hurdles of UI development.