The WebAssembly community should really focus more the developer experience of using it. I recently completed a project where I wrote a compiler¹ targeting it and found the experience to be rather frustrating.
Given that Wasm is designed with formal semantics in mind, why is the DX of using it as a target so bad? I used binaryen.js to emit Wasm in my compiler and didn't get a feeling that I am targeting a well designed instruction set. Maybe this is a criticism of Binaryen and its poor documentation because I liked writing short snippets of Wasm text very much.
Binaryen has a lot of baggage from Wasm early days, when it was still a strict AST. Many newer features are difficult to manipulate in its model.
In our compiler (featured in TFA), we chose to define our own data structure for an abstract representation of Wasm. We then wrote two emitters: one to .wasm (the default, for speed), and one to .wat (to debug our compiler when we get it wrong). It was pretty straightforward, so I think the instruction set is quite nice. [1]
For what it's worth, I also tried Binaryen from TypeScript and similarly found it frustrating. I switched to using wasm-tools from Rust instead, and have found that to be a vastly better experience.
Isn't wasm-tools for working with Wasm modules? Maybe I'm missing something. I was using Binaryen to compile an AST to WebAssembly text. Also worth mentioning that Binaryen is the official compiler/toolchain for this purpose which is why I expected more from it.
Currently you use Binaryen to build up a representation of a Wasm module, then call emitText to generate a .wat file from that. With wasm-tools you'd do the same thing via the wasm-encoder crate to generate the bytes corresponding to a .wasm file, and then use the wasmprinter crate to convert from the .wasm format to the .wat format. Alternatively, I believe the walrus crate gives you a somewhat higher-level API to do the same thing, but I haven't used it because it's much heavier-weight.
What were your specific pain points? One thing that can be annoying is validation errors. That's one of the reasons that Wizard has a --trace-validation flag that prints a nicely-formatted depiction of the validation algorithm as it works.
Validation errors were bit of an issue. Especially because Binaryen constructs an internal IR that remains opaque until we emit the Wasm text. I did consider Wizard for my project but settled on Wasmtime because I needed WASI support.
My major pain point was the documentation. The binaryen.js API reference¹ is a list of function signatures. Maybe this makes sense to someone more experienced but I found it hard to understand initially. There are no explanation of what the parameters mean. For example, the following is the only information the reference provides for compiling an `if` statement:
In contrast, the Wasm instruction reference on MDN² is amazing. WASI again suffers from the same documentation issues. I didn't find any official resource on how to use `fd_write` for example. Thankfully I found this blog post³.
Wasm feels more inaccessible that other projects. The everyday programmer shouldn't be expected to understand PL research topics when they are trying to do something with it. I understand that's not the intention but this is what it feels like.
Sorry about binaryen.js - those JS/TS bindings could be a lot better, and better documented, but priorities are generally focused on improving optimizations in core Binaryen.
That is, most work in Binaryen is on improving wasm-opt which inputs wasm and outputs wasm, so any toolchain can use it (as opposed to just JS/TS).
But if someone had the time to improve the JS/TS bindings that would be great!
i found assembly is easier to assemble from scratch (it's apple and orange but.). Most materials should exclude these tooling, mostly rust based tools. We should be able to write them by hands just like when assembly was taught. Compiler and assembly are separate classes. I think it's bad assumption that only compiler devs only care about wasm. It's compiling target, sure, but framing it this way will not broaden its knowledge.
I've tried using binaryen, and I've also tried emitting raw wasm by hand, and the latter was far easier. It only took ~200 lines of wasm-specific code.
Given that Wasm is designed with formal semantics in mind, why is the DX of using it as a target so bad? I used binaryen.js to emit Wasm in my compiler and didn't get a feeling that I am targeting a well designed instruction set. Maybe this is a criticism of Binaryen and its poor documentation because I liked writing short snippets of Wasm text very much.
1. https://git.sr.ht/~alabhyajindal/jasmine