Zig Made Me a Better Programmer

If you haven’t heard of it, Zig is a systems programming language with manual memory management. For the ideals that Zig was built with, here’s the Zig zen:

  • Communicate intent precisely.
  • Edge cases matter.
  • Favor reading code over writing code.
  • Only one obvious way to do things.
  • Runtime crashes are better than bugs.
  • Compile errors are better than runtime crashes.
  • Incremental improvements.
  • Avoid local maximums.
  • Reduce the amount one must remember.
  • Focus on code rather than style.
  • Resource allocation may fail; resource deallocation must succeed.
  • Memory is a resource.
  • Together we serve the users.

These ideals forged an interesting programming language. While Zig is interesting, it’s certainly not production-ready yet, so keep that in mind. But I don’t think that matters. In my opinion, Zig is a delightful language for exploring the vast landscape of programming.

In using Zig, I’ve learned about many things that I would’ve never even thought to explore. For example, I have a detailed understanding of different memory allocation strategies (and even how they’re implemented) thanks to Zig. Similarly, the need to read standard library code gave me a great understanding of how my code is running from top to bottom.

There are no black boxes with Zig. No hidden compiler functions1, hard-to-read macros, or concealed memory allocations. It’s just you and the code. Since bugs hide in the shadowy corners, there’s a lot less footguns in Zig.

I’m not saying Zig doesn’t have its problems (loops are weird, no interfaces, and the ecosystem is young), but the design feels like a lot of love was put into it. Everything feels thought out (once again minus loops), and you learn how to write idiomatic Zig code quickly.

You just naturally pick up an understanding of lower-level concepts by writing Zig code. It’s built into the language and the surrounding community.

Even coming from Rust, I mostly didn’t miss RAII. Arena allocators and defer were suitable replacements 99% of the time. That other 1% of the time, I had to do a bit more work to figure out where to free. But for me, *the overhead of Zig’s memory handling is way less than the overhead of working around Rust’s lifetime system2*. Maybe that will change in a larger project, but I’m doing just fine with it for now.

The main point I’m trying to make is Zig is a great companion for delving into various types of programming. It encourages good practices and doesn’t hide things from you. If that sounds like a good proposition, check it out.

  1. All compiler implemented functions begin with the prefix @ (ex. @TypeOf()). Things like formatting can be implemented in plain Zig, not requiring a specialized compiler implementation (like in C or Rust). [return]
  2. I also found myself using less efficient data structures (ie. Vec<u8> instead of &[u8]) while writing Rust code to work around lifetime limitations. [return]