Being just a single file with a simple build command it seemed like a minimal advancement on the state of the art, so I quickly decided to publish, and did not appropriately credit the original as I should have. I hope you can accept my apology – this was an honest mistake.
No problem Yuri, thanks for the credit and the apology! I do recommend writing articles based on doing the thing from scratch yourself though as you can write something more nuanced and interesting that way.
This is actually the second time this really basic example has been ripped off by someone else for internet clout.
It used to be a bit more complex and fiddly which is why I made the repo initially to gather some disparate info and my own contribution into one place. Now this is something you can put together with zero experience with Zig in a spare half an hour. Which really is as it should be with first-class support for WASM. I mostly maintain this because it's nice to have.
That sucks. I'm happy to flag this article, as it's rather light on content and stealing the little content it has is not cool. Recommend others do the same.
I've been working with Zig lately (after 2 years of rust), and I have to say that the lack of borrow checker allows a lot of flexibility. You might argue it is dangerous, but in some case it's ok.
I think Zig complements very well rust for some applications. And it is very exciting to have both. This WASM example shows how simple and straightforward it is.
I really hope that they are not going "to fight", by that I mean the communities and not the languages themselves. I've already seen some people being "religious" about one or the other (HN included), even insults. We should be very happy to have new tools to build better softwares and not fight.
I wish the very best to both communities and languages.
For a somewhat more complete example which runs in browsers, check out my little pacman.zig toy project [0]. This is cheating a bit by using the Emscripten SDK as 'sysroot' (needed for the Emscripten headers to provide the glue to web APIs), and the Emscripten linker to create the additional html and js output file, but the actual code is all compiled with the Zig compiler to WASM, emcc is only used for linking.
The interesting part is that the platform abstraction is provided by the sokol C headers [1], with auto-generated Zig bindings [2]. It's interesting because the C headers use "Emscripten magic" (mainly embedding Javascript snippets in the C sources via the EM_JS() macro), and the Zig compiler is able to compile this (when it has access to the Emscripten headers).
It would be nice if the "Emscripten platform" could get the same type of cross-compilation support as the desktop platforms eventually, but apart from bundling the Emscripten headers, this would also require to implement some of the "Emscripten magic" in the Zig linker.
Maybe projects like WaJIC [3] can help with this (this basically implements the "Emscripten magic" of embedding Javascript snippets in C/C++ source code, but without Emscripten (only the wasm-opt tool is needed AFAIK).
Anyway... it's a lot of fun to tinker around with this stuff in Zig :)
Zig is probably the most common tool to compile C/C++ to WebAssembly outside the browser, but the Zig language itself has first-class support for WebAssembly/WASI.
The resulting modules are small and very optimized.
Rusts wasm32-wasi and wasm32-unknown-unknown targets don't depend on Emscripten and they've been the preferred ways of targeting wasm for years now.
There is a wasm32-unknown-emscripten target but I think that's basically on life support if not outright deprecated. It was only really a stop-gap until native tooling like wasm_bindgen got fleshed out.
wasm32-unknown-emscripten is useful if you want to build a Rust program using SDL2 and GL for the Web, for example. But yes, as you said, it's much less used. Most Rust code on the Web is not a port of existing applications (which is what Emscripten focuses on), unlike C++.
Whenever there is a post relating to Zig, I can always rely on you to post negative comments for no real reason. I can understand not liking the language, but this is about the C/C++ compilation toolchain, which uses clang under the hood. Even if you think Zig is the worst language in the world, you can still use the toolchain without having to deal with the language at all.
I guess my fundamental question is, what does your comment add to the conversation? It seems like you're not even disagreeing with the fundamental premise; you just felt the need to diminish Zig simply because someone tried to acknowledge that it was useful for something.
Had the OP not stated that "Zig is probably the most common tool to compile C/C++ to WebAssembly outside the browser,...", I wouldn't have said anything.
You say it yourself, this is about the C and C++ toolchain offered by clang, ergo not Zig.
I only reply on hype regarding Zig, like the previous remark, or it being "safe", when it is as safe as Modula-2 already was in 1978.
Which while miles beyond C, it wasn't without flaws.
As for what adds to the conversation, I guess taming a bit the hype, regardless of the language.
If you are so attentive, you will have remarked that I spare no language, all get their share.
Finally, if you don't like my comments, page down is your friend.
What do you want from a net module? We're having an ok time using the built-in io_uring support in the stdlib, but there's not yet a generic event loop that abstracts over epoll/io_uring/select/kqueue/whatever Windows has.
Somewhat related, how does Zig compare to Rust? I've been learning Rust but also saw Zig gaining traction. I believe the JS runtime Bun is written in Zig which was on HN last week.
It tends to break down along the same lines as the C vs. C++ debate from 15 years ago.
People who are willing to accept a lot of complexity in order to solve certain problems or gain expressiveness tend to prefer Rust. It's a complex language with a rough learning curve and not-great compile times, but it does help solve some really difficult problems.
People who prefer simpler, more straightforwards languages (like C and Go) tend to prefer Zig. The core of the language is much smaller and more C-like, the (new) compiler is really fast and uses less memory in comparison to Rust or C++. The selection of features it does provide is very tasteful and clever in a way that has been really impressive. They do a huge amount with very little.
e.g.
* macros are avoided entirely by using compile time code evaluation and dead code elimination
* "generics" are implemented by using types as function arguments (no special syntax to learn) and compile time code evaluation
7 years seem to be a long time, but for something that operates on such a low level it isn't. Rust also exists for 12 years now, but got the most traction in the last 2-3 years.
From my point of view wasm is currently in a state where a lot of companies and people are learning. Most of the toolchains had to mature before the broader mass of developers (who have an interest in this technology) took a look into it.
Yeah, you are right, it is lesser used than e.g JavaScript, but tbh it also has a different target audience. You probably can build UI by using wasm. But why don't use JavaScript, which is way more comfortable and has a bigger community around it? (Unless you have some specific needs)
As a web developer you don't need wasm right now. If you are doing some lower level work (like trying to run AI models/training) and you really need the performance, then wasm gets pretty interesting.
Most of the cool wasm projects I've seen in the past few months/ years were open source ports of games or emulators compiled to wasm (like Doom 3 ), which really ran very great. And my guess is that the broader development community is currently doing exactly this: they are playing around with wasm to learn for what use cases wasm could be a great fit.
(more known Wasm users are for example Figma or Google Earth. Iirc I've read that BBC is currently exploring if they can use wasm for their media players)
It's already used for many applications, including smart contracts, function-as-a-service services, and for running applications such as Photoshop in Chrome.
It's also significantly faster than Javascript for some workloads, while still providing the ability to run untrusted/potentially insecure code in a sandbox.
We use WASM to provide in-browser Scrabble-like analysis at https://woogles.io at the end of games. The original analyzer was built in Rust and the speed is close to native.
The numbers I seen suggest wasm is 3-5x slower then native which isn't bad IMO. JavaScript is also 3-5x slower than native. Is JS close to native speed? I don't think you can say it about one but not the other
It is true you can find a specific benchmark where wasm is 3-5x slower, say if the original uses highly-tuned x86 SIMD or relaxed atomics (or if the wasm version has SIMD or threads turned off entirely). But in general, the overhead is much lower.
BTW, if there is a problem with the current WASM performance, it's probably SIMD.
Again, based solely on my own benchmarks, exclusively in the area I'm interested in (game-type workload, so, say, multiplying many small matrices, performing geometric tests), there is little to no speed-up from wasm-simd128 (where it is supported), whereas native code compiled from the same sources, by the same compiler, profiled on the same machine, seems to be running a bit faster when vectorized.
(As I said in another comment, those are 4 microbenchmarks. The links I provided contain both real-world codebases and also large sets of varied benchmarks.)
Curiosity is getting to me. Why on earth would you use wasm outside of a browser instead of a container like most people?
When you said I was wrong I knew right away you either never actually tested or you're talking about outside of the browser. If it wasn't clear I was talking about wasm in chrome/safari/firefox this entire time
And specifically SQLite is a benchmark that I've looked at many times over the years. It's an important codebase. That's why I added it to the Emscripten benchmark suite, and why it is measured in that last link.
(Fyi, I am one of the co-creators of WebAssembly, I created Emscripten, and I have been working in the compile-stuff-to-the-Web space for over a decade.)
1. Why wasn't realloc part of the spec? When I looked at wasm and emscripten it appeared that realloc was essentially malloc+memcpy? That'd be painful when arrays are bigger than L2 or L3 cache. I think I heard arm cpu's all standardized to have virtual memory in 2005 or 2010 so I don't think arm hardware was an issue?
2. It seems like 100% of system calls would have to be implemented through javascript? Why wasn't there some things wasm implemented itself like a way to get time or rdtsc, realloc and other very common operations?
For the second, WASI is doing that on the server, while on the Web we just haven't found a way that is better/faster than calling through JavaScript (we tried to do direct WebIDL bindings among other things).
But is this a failing of wasm or the system glue layer, that for something like sqlite/web has to go through js/browser/etc?
Yes, I understand the importance of real-life tests like this, but how one is expected to go about testing wasm performance as such other than using benchmarks that are mostly arithmetic/logic and not syscall-type code?
How you use it in real life has to be taken in consideration. From memory system like calls go through JS and there's no realloc. I didn't want to say it in my first comment because I notice the more someone writes the more likely others will argue. I rather someone else post the SQL benchmark but apparently everyone drank the kool aid and had no idea wasm isn't that fast. I certainly would rather use JS than write c++/rust. I wouldn't be surprised if that list of companies using wasm only use it for one or two large projects then stuck to js because of how much work wasm is
Depends on workload of course, but seems too pessimistic with the current state of WASM support.
At least this is not what I'm seeing with the things I'm working on (graphics-related), when comparing to native builds.
I have run benchmarks directly with the actual codebase running on my computer and then the WASM version and the WASM is about 70-80% of the speed.
Sadly, when the analyzer was written in Go, I was getting around 20-25% of the speed after compiling to WASM. I believe it is largely due to that code being very inefficient about allocations, and I think WASM doesn't like allocations/deallocations very much.
Those are 4 microbenchmarks. There are much larger and more realistic workloads benchmarked in other places (see https://news.ycombinator.com/item?id=32084768 for links), with very different results.
https://github.com/meheleventyone/zig-wasm-test
Thanks for the credit yurivish! :(