top | item 36149462

Zig is hard but worth it

401 points| signa11 | 2 years ago |ratfactor.com

298 comments

order
[+] latch|2 years ago|reply
I've now written a lot of zig code (http.zig, websocket.zig, log.zig, zuckdb.zig, etc.) I think Zig falls into an "easy to learn, average/hard to master" category.

Some insiders underestimate the effort required for newcomers to build non-trivial things. I think this is because some of that complexity has to do with things like poor documentation, inconsistent stdlib, incompatible releases, slow release cycle, lack of package manager, etc. For an insider living and breathing Zig, not only aren't these huge challenges, they aren't really "Zig" - they are just transient growing pains. For someone getting started though, the current state of Zig is Zig.

I wish Zig had a polished package manager (there's one in the current development branch, but you don't as much use it as fight it). They could then move some of the less polished code into official experimental packages, helping to set expectations and maybe focus the development efforts.

[+] zoogeny|2 years ago|reply
I've lately thought that a package manager is as essential to a new language as a standard library. I would also add a LSP and standard code formatter to that list.

It is a bit unfortunate because all of the above is a pretty tall order. We're getting to the point that new languages are expected to boil the ocean by the time they reach 1.0

[+] VyseofArcadia|2 years ago|reply
I used Zig for a weekend project and loved it, but I am resolved to not use it for anything else until it hits 1.0. I don't have time to write and re-write and re-re-write my code as the language and stlib stabilize.
[+] throwaway2037|2 years ago|reply

    I think Zig falls into an "easy to learn, average/hard to master"
Thank you for sharing an insider's account. I naively assume that Zig is not your first language. Regarding "average/hard to master", can you think of any of languages where this is not true? Zero trolling, I promise. My point: No language is any less than average to master. Even VBA has some weird stuff in it that used to catch me off guard when I wrote Excel apps years ago. To be clear, I would classify VBA as similar, but I would classify Python as "easy to learn, very hard to master", and Perl as "average to learn, impossible to master"(!).
[+] JC770|2 years ago|reply
I just start to learn Zig,any suggest to beginners?Bro
[+] cassepipe|2 years ago|reply
To get an idea, what is your programming background ? Are you a C or C++ programmer ?
[+] cztomsik|2 years ago|reply
In my case, Zig was super-simple to pickup, I've been using rust for few years so I was already in the systems programming (as a hobby), and I also had to read some C/C++ during that time, that probably helped me too.

Other than that, I was and I am, mostly a frontend developer with ECMAScript and TypeScript experience. I think Zig is very close to both, because Zig has anytype, so you can do duck-typing like you do in JS, and it has programmable type system, just like TS. Not to mention that reflection is basically your daily bread in JS/TS.

TLDR: If you have some systems programming experience and you've done a bit of TS, I'd definitely recommend you to give Zig a try. One weekend should be enough. I did that literally single-handed, as I was recovering after wrist surgery.

[+] helen___keller|2 years ago|reply
My main issue with Zig is that I’m scared to invest time in writing something nontrivial to see the community/adoption flounder then regret not using Rust or C++ later

The language itself is fun. The explicit-ness of choosing how allocation is done feels novel, and comptime is a clean solution for problems that are ugly in most languages.

Aside from lack of community I’d say the biggest nuisance is error handling in nearly everything including allocations. I get that allocation can fail but the vast majority of programs I write, I just want to panic on an allocation failure (granted these aren’t production programs…)

Edit: in retrospect, allocator error handling verbosity is probably necessary due to the power the language gives you in choosing allocators. If I use the general purpose allocator then my edge case is PC out of memory; if I use a fixed buffer allocator, a failed allocation is a code bug or a common error case, so we might want to handle the failed allocation and recover

[+] ldelossa|2 years ago|reply
I'm surprised that the reason I'm mostly interested in Zig is not mentioned.

This is C interop.

I work with C quite a bit and I enjoy it, however writing a large project in C can be tiresome.

Having an option like Zig which can import C headers and call C functions without bindings is pretty attractive, especially when you want to write something a big larger but still stay in C world.

[+] jsheard|2 years ago|reply
I get what Zig is going for in making all operations as explicit as possible, but I fear that it's going to turn away fields like graphics and game development where it would be a good fit except for the lack of operator overloading forcing you to go back to C-style math function spaghetti. It's all fun and games until what should be a straightforward math expression turns into 8 nested function calls.
[+] pron|2 years ago|reply
As someone who works on another language that is relatively reluctant to add language features (Java) we regularly face such dilemmas. A user shows up with a problem that could be helped by the language. The problem is real and a language feature would work, but there are many such problems, and adding features to solve all of them will make the language much bigger, overall causing greater harm (even those who don't themselves use the feature need to learn it to be able to read code). What we try to ascertain is how big of a problem it is, how many programs or lines of code it affects, and is there possibly a single feature that could solve multiple problems at once.

So I would ask you this: what portion of your program suffers from a lack of user-defined infix operators and how big of a problem is it overall? Even if it turns out that the problem is worth fixing in the language, it often makes sense to wait some years and then prioritise the various problems that have been reported. Zig's simplicity and its no-overload (not just operator overloads!) single-dispatch is among its greatest features, and meant to be one of its greatest draws.

[+] TwentyPosts|2 years ago|reply
I am not much of a Zig-head, but the best compromise I can think of is having a few operators which purely and solely exist for this purpose. In other words, there is no operator overloading, but you can define, say, "#+" for any two structs, or something like that.

So if you want to encode matrix multiplication, then you'll always have to write `mat1 #* mat2`. This feels like a hack, and isn't all that elegant, but it'd be clear that every usage of such an operator is a disguised function call. (And according to what Andrew Kelley said, it's all about not hiding function calls or complex operations in seemingly innocent 'overloaded' symbols.)

If you want to take this one step further you'd probably have to allow users to define infix functions, which would be its own can of worms.

Honestly, I am not particularly happy with any of these ideas, but I can't think of anything better either!

[+] bodge5000|2 years ago|reply
I'm no expert on zig, but the one area I have seen it shooting up in popularity is game dev. Though I guess that is largely as a replacement for C, so "C-style" wouldnt be much of a concern
[+] tuhats|2 years ago|reply
I have played around with using @Vector for linear algebra.

This removes the need for operator overloading for a vector type, which covers most use cases of operator overloading and I often in fact think is the only legitimate use case.

I don't get to use `*` for matrix multiplication, but I have found I do not mind using a function for this.

I have only been playing with this in small toy programs that don't to much serious linear algebra and I haven't looked at the asm I am generating with this approach, but I have been enjoying it so far!

[+] audunw|2 years ago|reply
I like Zigs justification for not having general purpose operator overloading (no hidden function calls and loops)

But I wish they added:

1. Ability to declare completely pure functions that have no loops except those which can be evaluated at compile time. Something with similar constraints as eBPF in other words. These could be useful in many contexts. 2. Ability to explicitly import overloaded operators, that can only be implemented using these pure guaranteed-to-finish-in-a-fixed-number-of-cycles functions.

Then you'd get operator overloading that can be used to implement any kind of mathematical function, but not all kinds of crazy DSL-like stuff which is outside the scope of Zig (I have nothing against that, I've done crazy stuff in Ruby myself, but it's not suitable for Zig)

[+] flohofwoe|2 years ago|reply
Zig has a builtin @Vector type that might come in handy for most cases where in C++ a math library with operator overloading would be used:

https://www.godbolt.org/z/7zbxnncv6

...maybe one day there will also be a @Matrix builtin.

[+] sigsev_251|2 years ago|reply
To be fair, there is an operator overloading proposal for C2y/C3a and there is at least one compiler that offers operator overloading as an extension.
[+] kapperchino|2 years ago|reply
For the math stuff you can do things like a builder pattern where you can flatten the nested functions. But operator overloading is definitely preferred
[+] pron|2 years ago|reply
> there’s not a direct correlation between the slimness of a language’s syntax and ease of learning

That's absolutely true, but (the standard library aside) the "syntax" -- or, rather the syntax and core semantics -- of a programming language are arbitrary axiomatic rules, while everything else is derivable from those axioms. So while it is true that a small language can lead to a not-necessarily-easy-to-learn overall programming experience, it is the only arbitrary part, and so the only part you need to memorise (or consult the documentation for when dealing with some subtlety you may have forgotten). So a smaller language reduces the need for "language lawyering" after you learn it.

Some languages (e.g. lisps) are deceptively small by relying on macros that form a "second-order" language that interacts with the "first-order" language, but Zig doesn't have that. It has only one language level, which is small and easy to memorise.

But yes, Zig is a bigger language than C, but a far smaller language than C++. What's amazing, though, is that C++ is strictly more expressive than C (i.e. there are programs that could grow exponentially faster in C than in C++, at least without the help of C macros), but Zig is as expressive as C++ (i.e. program sizes may differ by no more than a small constant factor) while being much closer to C in size, and it achieves that without the use of macros.

[+] the_duke|2 years ago|reply
I'm not a Zig expert, but I have a different take here.

Zig has comptime, which is essentially a compile time macro written in the main language and with type reflection capabilities.

They can introduce complex behaviour and fail in very cryptic and unexpected ways, which results in an experience very similar to macros or C++ template literals.

[+] ImprobableTruth|2 years ago|reply
You still have to memorize the "design patterns" that replace 'missing' features. Especially annoying for something like interfaces where there's a bunch of variants and people often use implementations with awful error reporting reminiscent of C++ templates.

Now, it's definitely neat that you can do reasoning from first principles on it, but I'm not sure how much of a gain that is.

[+] distcs|2 years ago|reply
> Some languages (e.g. lisps) are deceptively small by relying on macros that form a "second-order" language that interacts with the "first-order" language, but Zig doesn't have that.

What are some other examples of such languages that rely on second-order languages? You mentioned Lisps. Would Forth be another example? Are there more examples?

[+] thadt|2 years ago|reply
> Crucially, there is basically no documentation for the standard library except for the source code itself.

From the viewpoint of someone learning about a new language, I find the accessibility of the standard libraries goes a long way toward helping me understand how things fit together. It is a first stop to see how experts in the language use it. Browsing through the standard libraries of languages like Zig, Go, and Python - they're usually well-documented and readable enough to be a tutorial, even before you've dug into learning it. Others (Rust, C++) are a bit more, ah, technical for the novice.

[+] TwentyPosts|2 years ago|reply
Afaik Zig has the issue that basically everything happens on the Discord server, where it can't be indexed via search engines, or found by anyone who wants to have a quick question answered. This would be "fine" if the standard library and language were much better documented, but it isn't, and it's still ripe with bugs.

In other words, you're forced to use the Zig Discord server if you want to find answers to any simple questions, and this is (sadly) not obvious at all to newcomers to the language.

[+] Vecr|2 years ago|reply
Rust has the standard library documentation at https://doc.rust-lang.org/std/ or on your local computer, if there's really nothing like that for Zig I think that's a problem. Are you sure there's no `info zig` or something like that?
[+] tialaramex|2 years ago|reply
I certainly wouldn't recommend trying to figure out C++ by reading either of the three major C++ standard libraries.
[+] rayiner|2 years ago|reply
Alternative languages are cool, but I struggle to see the point of a systems programming language that doesn't offer static memory safety in 2023. Rust isn't necessarily the best and final answer--it seems like there is a broad design space to explore for memory-safe systems programming languages. But Zig seems to occupy the same local maximum as C--a relatively simple, non-safe systems language--and doesn't have a killer feature that justifies not just using C.
[+] haberman|2 years ago|reply
The killer feature of Zig IMO is comptime. C++ has spent over a decade now marching towards making more and more of the language available at compile time, but in an awkward and complicated way (constexpr, consteval, constinit). Zig comes out of the gate with a unified and coherent compile-time evaluation feature that effectively obsoletes not only constexpr/consteval/constinit, but C++ templates too. This is "doing more with less" in a way that I find really compelling.
[+] helen___keller|2 years ago|reply
If we’re comparing C to Zig I’m not sure what memory safety even needs to be mentioned for.

For C to Zig there’s plenty of reasons one might prefer Zig. For memory safety obviously you might opt to choose neither.

[+] krupan|2 years ago|reply
Honest question here (that I have every time I see someone talk about memory safety in 2023), are you aware of Ada/Spark?
[+] Decabytes|2 years ago|reply
Zig is not my favorite language to program in, but I think it's focusing on a lot of the right stuff.

1. Easy Build System 2. Drop in Replacement for c/c++ compiler (zig cc) 3. Easy cross compliation 4. Single executable compiler 5. Package manager 6. Debugabillity

It's the sort of developer focus that has a huge impact especially when you are doing it for more than just a hobby. Crystal, another language I love, is weak in this area. No tree sitter, No tier1 windows support, Major libraries like the Lucky Framework that don't build on Windows, a buggy LSP etc. Don't get me wrong I love the language, and I will continue to work in it, and all of these things are in various states of progress, but it's already at 1.8 and some of these issues haven't been ironed out yet. I'm not just armchair complaining, I know these are hard, and I will contribute once I am more familiar with the language

[+] jeroenhd|2 years ago|reply
I like Zig as a concept, but every time I've tried it, the toolchain lacked good IDE and debugger support. I've tried some plugins half a year ago but they either didn't work reliably or they missed important features. I'm personally sticking with Rust until the day comes that I can just add a VSCode/Clion plugin that'll give me an interactive debugger with full autocomplete support without fiddling around too much.

There's a lot to like with Zig, despite its unconvential syntax and some language decisions I personally disagree with. The language is still in development but it's very promising and I'll definitely try to learn it before it reaches that magical 1.0 release.

[+] ok123456|2 years ago|reply
One annoying thing I ran into when trying zig is they don't distribute debs any more for Debian distributions. They just tell you to use a snap. I don't have snap, and don't want it.

Compiling it requires the latest llvm toolchian (16), which is only realistically going to be available as a package if you're on a bleeding edge distribution.

[+] AndyKelley|2 years ago|reply
let me clarify some facts.

1. we never distributed debs for debian distributions. I have, however, been patiently collaborating with Debian maintainers with regards to the zig ITP: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=995670

2. we don't tell you to "just use a snap.". Please see https://github.com/ziglang/zig/#installation

3. we tag releases soon after llvm tags releases for the convenience of package maintainers. Distributions with LLVM 14 can package Zig 0.9.1; distributions with LLVM 15 can package Zig 0.10.1, etc.

[+] pacaro|2 years ago|reply
I understand this, but haven't found this to be an issue personally. I just download the pre built tarball, expand it, make sure that /opt/zig-latest symlinks to the right folder, and setup path

That's more work than apt-get install for sure, but not so much more

[+] eatonphil|2 years ago|reply
What's wrong with downloading the binary? curl + mv + chown should do it?
[+] parasense|2 years ago|reply
The main take away is:

> Something that makes Zig harder to learn up front, but easier in the long run is lack of undefined behavior.

Reminds me of the old discussions of Fortran Vs C, and specifically in the early times before C had a standard library. What we call "undefined behaviour" was just an idiom of the language where the "behaviour" was sometimes on purpose, but recognised might not be portable. And so the point here is the idea of undefined behaviour is tied to portability on some levels, and isn't just some purely academic idea about the compiler or abstract syntax trees.

So I'm concerned about the potential over-zealous prejudice against undefined behaviour, but I think we can all agree deterministic software is better than otherwise. The catch is that sometimes UB is deterministic, and yet dares to not be idiomatic.

[+] nickelcitymario|2 years ago|reply
> [...] easy things seem easy primarily because they are familiar. Easy is subjective. But simple things are simple because they do not complicate; they have fewer concepts. Simple is objective.

This should be printed out as a large poster in every office.

[+] michaelcampbell|2 years ago|reply
I don't know Zig so I can't comment much on the content, but the author's writing style I enjoyed immensely; enough to make me want to pick up Zig for fun. I do have some C background, albeit decades ago, so maybe I'm in the right spot for it.
[+] frankjr|2 years ago|reply
I've been playing with it and so far but I'm more impressed with their build system rather than the language itself (it seems to be way more flexible and simpler than alternatives which is pretty rare). They did however get the module system right. You can just organize the file structure in any way you like. I hate Rust's "everything is a single module" system with passion.
[+] sarchertech|2 years ago|reply
I tried Zig for a few weeks but ended up choosing Odin for a game dev side project I’m working on. Odin feels a lot more high level, but still gives you low level control when you need it.
[+] cies|2 years ago|reply
From the article:

> Easy is subjective. But simple things are simple because they do not complicate; they have fewer concepts. Simple is objective.

I'd argue both are subjective, or with a better word: relative.

I'd say Zig is easier and simpler than C in almost all regards. The article does not specify what Zig is compared to in order to make these statements. Probably the author had C in mind, but that was not explicitly mentioned.

[+] jasfi|2 years ago|reply
Nim isn't hard, it just has a small community.
[+] thih9|2 years ago|reply
> "I learned Zig in a weekend! … Six hours! … 6µs!" say the blissful lizards.

I don’t get it; is this a reference? Could someone explain?

[+] bakuninsbart|2 years ago|reply
Where do you guys see good use cases for Zig? I'm intrigued by the language but don't really have any good ideas on where to try it out.

I thought about trying it out in as small data engineering project, but I'm not sure if language support is sufficient for the kind of tooling I would need eg. Database adapters.

[+] chjj|2 years ago|reply
Do you maintain any C projects? Personally, I tried using zig for its build system (which can also compile C and whose build files are written in zig). One of the benefits of this was easy cross-compilation to all major platforms.

It might not be a _real_ use-case or anything, but writing a `build.zig` file for an existing C project might be a good way to at least dip your toe in the water.

[+] askkk|2 years ago|reply
In new last version 0.10.1 it seems that for is not working with two arguments?

  const std = @import("std");
  const expect = std.testing.expect;

  test "for basics"  {
    const items = [_]i32 {4,5,3,4,0};
    var sum: i32 = 0;
    for(items, 0.. ) |value,_| {
      sum += value;
     }
     try expect(sum == 16);
  }

  ubuntu 22.04, snap zig version 0.10.1 , 
  zig test 1.zig produces:

  1.zig:7:12: error: expected ')', found ','
  for(items, 0.. ) |value,_| {
           ^
Edited: To update, I tried snap, but using snap install --classic --beta zig is a security risk because it can change the system and is not sandboxed.