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.
Throughout 2023, there was a discussion on Rust vs Zig and what to adopt based on our needs.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). ↩ Keep that in mind as Zig has evolved quickly, 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 dumping my thought because I had never witnessed a new core language being adopted at a company, and the kinds of considerations when your code must run on a large variety of targets and that might be ran by 100s of millions of users. I think the conversation that happened showcases the human factors to consider pretty well
What follows is a bit of an amalgamation of the discussion we had over the months. They do not always reflect my own opinions. I was mostly following along these discussions and had already settled for Rust for my own team in the end, that valiant piece of Rust that served 30-50k RPS in 10-12ms per request for a couple of years was rewritten in reactive java (and yet it still serving mobile clients!) ↩.
Also, some of it is wrong! Or idealistic! Everyone in the conversation 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, etc. 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 Arguments: Maturity, tooling, ecosystem, memory safety
- 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 sponsorshipsThe Rust Foundation has backing from major tech companies including Google, Microsoft, Meta, Amazon and others. ↩ 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”
- “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 behavior. 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 were referencedThe team referenced programming-language-benchmarks.vercel.app comparing Rust vs Zig performance across various computational tasks. ↩
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 came along with great possibility for high-level Python bindingsPyO3 (github.com/PyO3/pyo3) provides Rust bindings for Python, and pyo3-asyncio (github.com/awestlake87/pyo3-asyncio) adds async support for Python-Rust interop. ↩
- Serving a few C bindings for Rust for some of our 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
†Zig Arguments: Simplicity, C interop, cross-compilation, toolchain integration
- 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(c)(3), whereas the Rust Foundation is a 501(c)(6).501(c)(3) organizations are charitable nonprofits with more transparent financial reporting requirements, while 501(c)(6) are business leagues with less stringent disclosure requirements. ↩ 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 one 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
Footnotes
- 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). ↩
- in the end, that valiant piece of Rust that served 30-50k RPS in 10-12ms per request for a couple of years was rewritten in reactive java (and yet it still serving mobile clients!) ↩
- The Rust Foundation has backing from major tech companies including Google, Microsoft, Meta, Amazon and others. ↩
- The team referenced programming-language-benchmarks.vercel.app comparing Rust vs Zig performance across various computational tasks. ↩
- PyO3 (github.com/PyO3/pyo3) provides Rust bindings for Python, and pyo3-asyncio (github.com/awestlake87/pyo3-asyncio) adds async support for Python-Rust interop. ↩
- 501(c)(3) organizations are charitable nonprofits with more transparent financial reporting requirements, while 501(c)(6) are business leagues with less stringent disclosure requirements. ↩