Rust vs Zig Error Handling

Alice Turner - Jul 22 - - Dev Community

Recently, I’ve been considering whether Zig might be a better fit for developing a game engine due to its focus on simple code, transparent control flow, and control over allocations. Zig resembles C in its bare-bones approach, requiring programmers to manually build their structures and algorithms.

My programming philosophy is to keep things basic and minimal. Over-abstraction can lead to less intuitive and bloated code. When I first heard about Zig, I was excited to try it out. However, I felt it needed more time to mature, so I set it aside for a while.

In the meantime, I’ve been refining my understanding of Rust, a language I started learning at the beginning of 2023. I read the 2021 edition of “The Rust Programming Language” book, which I purchased to support the authors. I’m glad I did, as it provided a solid foundation in the language.

Since then, I’ve been developing hobby projects in Rust and supplementing my knowledge with additional books. As Zig gains traction, I’ve heard claims that it’s faster than C and other positive comments. So, I decided to put some of these claims to the test.

First, I tested the assertion that Zig’s general-purpose allocator (GPA) is faster than Rust’s, which uses libc on Linux and the Microsoft Visual C Runtime (MSVCRT) allocator. I wrote applications in both languages that looped over a function 10 times, each time running an allocation 100,000 times, assigning “hello world” to the allocation, and then exiting the function. According to my test, Rust was 1.89 seconds faster than Zig using the GPA. Both applications were built using their respective release modes. I don’t fully understand the resulting assembly of the Rust application, but it seems that heap allocations are optimized away. This might not be the best test since the Rust application isn’t doing the same as the Zig application, which explicitly requests a heap allocation.

Another important aspect is error handling. Zig uses a union type for errors, while Rust can use an integer type, dynamic allocation, and dynamic dispatch, either statically or in a hybrid approach. Initially, I liked Zig’s approach because it seemed to avoid slowing down error handling. However, I decided to test my Rust skills and developed different ways of handling errors, eventually settling on a hybrid approach.

In Zig, providing dynamic errors involves using a string allocation, as the bytes need to live past the stack frame they are allocated on. This requires dynamic sizing since the contents may change at runtime. Zig follows the rules of computer science but avoids hidden allocations, making them obvious when programmer.

In contrast, Rust’s standard library uses the Box type, which involves dynamic dispatch and a heap allocation. These allocations are limited to when the .into() method is called on an error or the ::new method is invoked. These calls are rare, and most uses of errors in the standard library are static strings stored in the binary.

In conclusion, Zig and Rust take different approaches to error handling. Neither approach is wrong; both are valid. Zig results in smaller binary sizes with predictable control flow, while Rust generally produces larger binaries with compile-time optimizations that make the resulting binary more of a black box. Rust requires more understanding and is more opinionated, but over time, it offers more control and flexibility, leading to hybrid approaches.

I’ve tried to be as fair as possible. Both languages have their strengths and weaknesses. I recommend both languages: I’m encouraging my son to learn Zig for its simplicity, but for production and scalability, I prefer Rust for its expressiveness and optimizations.

I hope this helps people assess the differences between Rust and Zig. Best of luck on your programming journey!

.
Terabox Video Player