Thoughts on the recent update to Zig
Recently, Andrew Kelley made a pretty serious proposal on the Zig repo. The intent is described as:
This issue is to fully eliminate LLVM, Clang, and LLD libraries from the Zig project.
What this means is that the Zig project (Andrew most likely) has the idea of dropping support for Clang and LLVM entirely, meaning that with that drop, Zig has no intention of cross-compiling C++ code for multiple platforms other than ones listed.
Zig was the only compiler toolchain for the longest period of time that enabled users to easily cross-compile C++ code from one platform to another, pretty much simplifying really horrible things like compiling SDL2 code from Linux to Windows. Zig does this by bootstrapping and providing a lot of necessary materials and doing a lot of work that would be considered annoying for most people. Zig provides a support table describing different architectures and CPUs that Zig can compile code to.
The aim here seems to be separating Zig from that of LLVM, because with all of LLVM's problems are often made Zig's problems, and Andrew (I imagine) doesn't want to be a support zone for LLVM problems when Zig users run into unexplained errors. Separating Zig from LLVM would mean Zig errors are actually Zig-related, and not due to LLVM weird problems like outdated versions across dozens of different versions of operating systems.
But, while I was reading this thread, it struck me that while I understand integrating LLVM with Zig is a pain in the butt to maintain long-term, the amount of users pouring in describing their pipelines was shocking. Zig really was gaining popularity for cross-compiling C++ code. I was shocked to see a developer for Baba Is You in the thread describing how he used Zig to help ship games.
So, I want to digest this news, and process it piece by piece and see what the intent for Zig is here, and what the outcome will inevitably become as Andrew develops this proposal further. It has been accepted, and Andrew has made it clear he calls the shots here, and not the users.
The big thing about removing LLVM entirely from Zig would be the ability to compile C++ code, and the ability to cross-compile C++ to multiple targets. Zig itself is a pretty large binary, and requires a ton of files for compilation of mostly any target. I think the last time I checked, the Zig binary itself and all files included was somewhere about 150MB of files altogether, maybe more.
The ability of
zig build was for the ability to write a
build.zig file which describes your build process. The
std.Build API is a toolkit for describing a build pipeline in steps, in which you can include things like shared libraries (
.so files) to dynamically link into with symbols, or you can create static binaries by which you compile external libraries into your code. This makes binaries larger, but all your code is self-contained and not reliant on external shared libraries on the target system.
To do the static part, which is a very alluring prospect of Zig, you must compile code as part of an all-in-one bundled compilation phase. Source code must be compiled for the target. A lot of libraries are indeed written in C, and more are written in C++. If you look at SDL library, it's written in C and C++, which means compilation is reliant on a good C compiler and a C++ compiler. For Linux this is solved mostly by
gcc, so not a big problem there, but for targets like Windows, you'd need their compilers as well, most likely Visual Studio C and C++ compilers, which is kind of annoying.
The other method is using Windows-friendly compilers like MinGW to target MSYS environments. The problem with MinGW is that it might not be the best environment for things like DirectX, which are Microsoft-made libraries, so there could be a large amount of incompatibilities. MinGW is also not really an official platform for the code it uses, namely the GNU Compiler Collection (GNU-CC). The GNU organization really only cares about free open-source platforms, and anyone using MinGW has to remember that MinGW is run by volunteers who may or may not be tied to GNU at all.
Zig has (or, I should say, still has) the ability to cut out the middle-man and use LLVM to generate LLVM-level IR which can compile to any target LLVM supports, which is a lot. This means Zig can act as a drop-in compiler for GCC, both C and C++, which is a pretty darn big deal, and cross-compiling on Zig is as easy as defining a
-target=<target_arch> flag. Zig providing support for cross-compilation is a step-up from the world of things like Autoconf, CMake and Meson, where third-party tools had to be used to generate Makefiles to support a given architecture. By using
build.zig, you can do without Makefile generation entirely, which was a very powerful step.
With that gone, the intent is that the C++ build step of Zig would be moved to an "independent party", and mainted by that group instead. What's not clear is who will be running that show, and if it's of utter importance to thousands of people, how is it going to be managed if it's separate from that of the Zig foundation?
Overall, this is a huge loss for Zig, and losing Zig-official support for building C++ is a problem, and poses future problems should the tool not be well-supported in the future. What will this C++ building system look like next year? Or in five years?
Zig relies a lot on LLVM for not only the C++ building facilities, but also the optimization passes that LLVM has. LLVM is a large public-facing project with thousands of contributors from independent parties to large corporations. LLVM benefits many corporations and has a lot of interest in making better, so much that new chip manufacturers can submit their patches to LLVM to be sure that developers can actually work on their new chipset.
LLVM has a lot of optimization patches submitted for many architectures, and with these patches, code can run faster, more efficient, waste less cycles and burn less power/battery. Seems promising, and you can wonder why Zig initially used LLVM as a backend, since LLVM covers so much ground already and has at least 20+ years of work covered.
However, should Zig decide to stop using LLVM, they will be losing out on not only their support targets, reducing their usage across the market, they will also lose out on performance optimizations that LLVM can employ.
Maybe it's not a big deal, but I would be more okay with knowing my code was optimized to be as fast as it possibly can be, so I'm not blowing through memory or power budgets. The machine can't do everything, but each and every architecture has tricks, and on top of that, there's also security patches as well. Zig losing out on both means that the code generated by Zig is less likely to be as fast as a LLVM backend Zig, and less likely to be safe from memory bugs. That doesn't sound ideal, frankly.
If you want to sell your language project to someone, you have to make it as sturdy as possible. This setback from LLVM unfortunately means that Zig is not going to appear to be as appealing to some now. Zig lacks the ability to perform object-oriented programming, and since Zig is a language with non-implicit control flow, why would you pick Zig when you can use C++ for object-oriented design?
Since Zig prefers explicit over implicit, would you use a language that doesn't make it easier to do composition over inheritance? Golang uses type embedding, Rust uses traits, and many other languages have simple syntax or macros to help encourage it. Zig's philosophy makes it more akin to C, but being 1-to-1 comparable to the C language isn't a blessing for developers, especially considering you want to be able to shrink your bug-writing vectors as much as possible and write less code more efficiently.
A lot of this comes from the fact that Andrew (and other members of the Zig core team) not wanting to carry LLVM's burden. I think that's a fair statement. Nobody wants to be the bag holder of technical debt, and the Zig team has run into that countless times.
This is slightly akin to Red Hat changing their licensing for CentOS. Red Hat got sick of being the people responsible for solving other peoples' problems (for free), and Zig I'm sure feels the same way. When people build Zig projects but have LLVM issues, they come to Zig, not to LLVM. Andrew would likely want it to be "when you have a Zig problem, it's actually a Zig problem".
I agree with Andrew about this, and I think it's the best way forward for a language to move upwards. However, I think the Zig userbase will shrink slightly due to the other changes in part.
comptime functionality. Maybe the
std.Allocator type is interesting to think about, but I imagine developer interest is really in Rust or Go at this point.
Maybe my imagination is running wild, but really, as much as I like Zig, part of me is coping with the hopes of a new language that is just different from the rest. But if I were to have a penny for each bit of annoyance Zig gave me, I'd have some pennies.
Allocator. Is it static? Does it live within functions? Do we re-assign it? What are the best practices around the
Allocator types itself?
usize is a type that exists, but really, I don't think it should at all. It's just a glorified
comptime_int, which should really be a
build library has changed so many times now I cannot trust
build.zig to be safe at all between Zig versions
switch when comparing
u8 with an enum typing of
x as T syntax for quick casts, but doing
@intToFloat() was absolute pain.
There's probably many more pain points I have with Zig, and while I was okay with some things then, it seems like creating a smarter language is not on the agenda. I think I might be better off spending my time with languages aimed at reducing developer work rather than trying to strive for parity with the C language itself.
Zig's goals are ambitious, but I do not know if I would qualify for being a Zig user in the future. I have small projects written in Zig, with aims of shooting higher, but now I have to ground myself in the reality that Zig is constantly changing, and isn't likely to be stable... Probably ever? Not really sure.
The ambitions of having Zig reach LLVM levels of support and optimizations and all that other stuff is a little too ambitious in my eyes, and even if Andrew and Loris are hard at work on Zig for the rest of their lives, I don't think they're going to reach the levels that LLVM performs at currently, much less get the donations required to bring more support on-board. If Zig's goal is to reduce itself to being a simple language that can do cross-compiles by exporting to a C language, then it's really not doing anything differently than say Nim, which can do similar things with a much simpler language, if Nim's main author wasn't having hot takes on his forum like this.
I haven't done much coding as of late, but I may start to write some new/similar projects in other languages to get a feel and expand my skillset with other languages. I felt it slightly relevant for me to write my thoughts on the Zig situation, and perhaps I'm wrong in some areas and would love to get some valid criticism or other opinions on the matter. All in all, I don't feel comfortable allocating more of my time to Zig, nor do I feel it appropriate for me to recommend it with this new proposal in place.
Things I might spend time with:
That's all I got for now. Take care and thanks for reading!