Zig vs Rust at work: the choice we made
Intro
At [redacted], we serve hundreds of millions of users. We use C and C++ in some of our core systems which end up servicing some of our most important features.
For context, when this discussion started: there was about 100 LOC of Zig at that point in the codebase, and a single service in Rust(an edge-distributed API compiled to WASM).
Throughout 2023, there was a discussion on Rust vs Zig and what to adopt based on our needs. Keep that in mind as Zig moves fast, and some of the arguments against it are already things of the past.
To make it incredibly simple, our needs boiled down to:
- C interoperability
- How easy it is to scale the codebase with engineers (eg hiring, maintaining)
Spoiler: we ended up choosing Zig. I won't go into too much details: I am mostly sharing that because I think that it gives a great insight as to the kinds of considerations that take place in a company where your code must run on a huge variety of targets and that might be ran by 100s of millions of users. I think the convo shows well that "fast code" or "memory safety" aren't the only factors to be considered.
What follows is a bit of an amalgamation of the discussion we had over the months -- they do not reflect my own opinions. I was mostly following along these discussions, and had already settled for Rust for my own team due to our specific needs. Also, some of it is wrong! Or idealistic! Everyone in the convo either loved Rust, Zig or both, and everyone wanted to make sure we made the right choice.
On the importance of C interop at [redacted] in the [redacted] team
The library we intended to rewrite had potential to be used on every platform we are on. We're pretty much on every platform: web, mobile, VR headsets, gaming consoles, on desktop. The only way to guarantee we can run on all these platforms is to provide a C API and use it via FFI. We also had other libraries which we wanted to be able to glue and build together with the one we were aiming to rewrite.
The main arguments
For rust
- Rust, at the time, was nearly 25x more popular than Zig, going by surveys and subreddits. This was used in the conversation re: ease of adoption, hiring, etc...
- Rust has been around in a stable state for much longer
- The Rust Foundation's industry sponsorships was reassuring vs Zig's more uncertain setup.
- The Rust LSP was unequivocally loved by everyone who tested it -- it holds your hand and it overall felt like an amazing experience.
- Cargo is an industry-leading package manager in terms of quality and DevX
- Memory safety and "no undefined behaviors" (obviously untrue, but that was the belief and part of the conversation we had to have
- "If we're going through the trouble of moving away from C++, then it doesn't make sense to go halfway and still have potential memory errors and undefined behaviour. Why not go all the way?"
- SIMD in Rust's std lib is available in
nightly
- WASM support was just as smooth in Rust as in Zig
- Rust and Zig were equivalent in performance for our needs, but in the cases where Rust was faster, it was noted to be "substantially faster" -- benchmarks such as https://programming-language-benchmarks.vercel.app/rust-vs-zig were throw around
On C interop with Rust:
- One of the main arguments was that C interop matters a lot more for zig, as it had nearly no ecosystem to speak of, whereas rust had rust-first libraries for nearly everything we needed.
- Rust along came along with great possibility for high-level Python bindings such as https://github.com/PyO3/pyo3 and https://github.com/awestlake87/pyo3-asyncio
- Serving a few C bindings for Rust for some our of programs was argued to be inconsequential when the rewrite would take months anyway and the benefits of using Rust would make the project easier to maintain for years to come.
For Zig
- Easy to learn if you know C/C++, or even TS.
- The language is a joy to write if you come from a ~C background.
- Zig's compiler: it's also a C and C++ compiler. This means we can pull any dependency we need and can build a C ABI library for any platform we support
- Very, very easy to support N target platforms. Zig makes it insanely simple to ship to consoles, mobile, web, desktop, etc...
zig targets
was mentioned and beloved. - Easy to write really fast software with it: native
Vector
support that leverages SIMD, no RAII, full-on memory management, etc. - Zig works with debuggers our developers know out of the box.
- The Zig build system is amazing and 100x better than our makefiles.
- The Zig Software Foundation is a 501©(3), whereas the Rust Foundation is a 501©(6). This has implications on disclosing more or less of the financials of the foundations, with Zig being substantially more transparent.
- Possible to port part of our C++ code to the eventual Zig library and "zigify" it later.
- 100% sure there won't be linking/compiling issues against the targets we need to support.
Conclusion
Zig significantly reduced the time and effort required to port our existing codebases and to ensure compatibility across all our platforms. The team couldn't be convinced Rust would make it as simple.
I did not go into a lot of the details, PoCs, etc that happened during that period. All in all, it boiled down to own very passionate individual and his choice will echo for decades and play a small part in the experience of what is most likely to be more than a billion unique users over time.
I think what I found the most interesting thing was that the things that ended up tilting the decision one way or another weren't what I expected:
- ease of learning and hiring played a much larger part than I thought it would, and played in Zig's favor
- developer experience around the toolchain also played a massive part
- the Zig compiler and build system again, tremendously helped it due to our needs and existing codebases
- the ecosystem and community of Rust, along with the memory safety insurances had way less impact than I imagined