Questions from a beginner dev about Zig

Hey everyone!

I’m currently a highschool student, mostly experienced with Python and a little bit of Rust. Before I commit to learning Rust, I wanted to ask you how your experience is with Zig.

How is the developer experience compared to Rust? I’m planning to mainly write web backends mostly interfacing with a DB (probably going to be Postgres), so I’d need something like tokio. How does package management work in Zig? I’ve heard of Jetzig and Zap, but I’m wondering if it’s better to write your own web framework in Zig if it can reduce the complexity compared to Rust and tokio. I’d also be displaying the contents of the DB on a webpage or mobile app, by polling the DB every few minutes. I’m also interested in writing desktop apps, but that’s a secondary priority.

Also, how’s the future for Zig? It’s not stable yet, but I really like this small hacker community around it. I feel like Rust is starting to lose it’s hacker-esque community since corpos and AI bros have been embracing it (cough cough bun).

Is the memory safety hype really such a big deal? Are there any ways we can reduce these vulnerabilities and what not with Zig?

And finally, are there any other resources I can use to learn Zig other than the standard reference handbook? I’m refusing to use any AI/LLM tools because, you know, I’m actually interested in learning this.

Please let me know, thank you for reading!

21 Likes

For me, the development experience has been pretty good. Mistakes usually lead to compile errors, or runtime errors with stack traces, rebuilding tends to be fast. On the other hand, the stdlib changes often, and the language is still in development. I am happy that the core team is willing to make changes like this, but it does mean that there’s a bit of churn when a new version comes out.

For backend web development, HTTP, interfacing with libraries, and so on, Zig has a couple of libraries, but the ecosystem is nowhere near as mature as for e.g. Rust. Zig’s equivalent to async runtimes, implementations of std.Io, are also still in their infancy. So, if you want to build web apps today, Rust might serve you better. On the other hand, going with Zig might give you some additional learning experiences.

As for AI bros and corpos, Zig (unfortunately) has quite a few AI bros among its fans. That said, the core team is anti-LLM, as is a good chunk of Zig users.

Memory safety is important, Zig and Rust have different approaches. Zig tries to avoid memory unsafety with optional runtime safety checks and patterns that make them harder to commit and easier to detect. Rust instead has a subset of the language that makes it impossible to cause memory safety bugs, and you can opt into memory unsafety with unsafe. This is why people call Rust memory-safe. These have upsides and downsides, but if you’re doing a lot of memory-unsafe operations, Zig will probably be more fun.

Check out this post for resources: Zig Learning Resources

11 Likes

Welcome! I found ziglings helpful when I was starting. It’s a bunch of examples with small bugs that you have to fix, and lots of comments and explanations. Very hands-on learning. It’s been a few years since I worked through it but it seems to be up-to-date.

I also find it invaluable to have my editor hooked up to ZLS and the standard library, so that I can easily discover or remind myself what sorts of things the standard library can do (and learn some code tricks by reading the source!)

4 Likes

I am not sure if that extends to refusing to use a search engines, but be if you do you use those, be aware that, because of the language (and stdlib) being in development, you run a very high risk of getting (pointed to) outdated answers.

The standard documentation is your friend, keep it open in a tab in your browser. It links to the Zig Standard Library keep it in another tab (online or via running zig std).

If you look at code from another project (for ideas, to see how things were done, or to link against it) check the Zig version used. Look at .minimum_zig_version (in build.zig.zon) and in general assume that if you use a higher minor version number, you are not going to be able to use the code as-is.
( if you really want to use code that was made for older versions, reading through the release notes, (I recommend in reverse order), will help, but may also distract from what Zig expects now )

And then there is this forum, if you have specific questions. (Provide a minimal example if you can).

4 Likes

Yes, not because it’s not important, but because the highest priority is not memory safety, but the overall correctness of the program, which is a strict superset of memory safety.

Whenever I hear people talk about memory safety with strong emphasis, it registers in my mind as not being as interested in tackling other bugs with the same intensity. If you start doing Rust try not to get into that mindset.

Less mature. We’re still in the process of introducing a new async I/O system, for example.

It’s not as big of a gamble as it used to be, but Zig it not a mainstream language. You get to enjoy the “we’re the rebels” feeling, but plenty of things are still unstable and will take a while to finish.

Chances are that, whatever choice you make, all will be fine in the end. Doing Zig will help you hit the ground running in the future with Rust, and vice versa. If you end up coming back to Zig a few years from now you will only find a more mature ecosystem, and so on.

19 Likes

Just wanted to share my personal experience too. First, I’m not a professional dev who earns big buckets coding important things (but as sys-admin at least have deeper insights into mainly Linux OS). Coding is mostly fun for me.

I started out with Rust as my first real programming language capable of doings high and low-level stuff. It was fun and I was even able to built some stuff others really like to use (still crazy to me thinking about it :smiley: ). However, working with Rust always felt somehow complicated.

Short note: I also refuse to use AI/LLM. I don’t like the concepts, as well as the political and environmental downsides. Plus, as said, coding is fun to me, why should I outsource it to a machine…

When I heard about Zigs move to Codeberg middlefinger up to Github and Big Tech, it was the one thing that made me switch.

Now, that I use it for about 7 months I almost fully abandoned Rust. Zigs syntax etc. is just much cleaner and not so verbose. No more endless chaining of methods as with Rust. Of course, there are not as many libs; its not even close. So you have to implement more on your own. But thats fine. And because of less available up-to-date docs you often have to look into the source code of stdlib and deps on your own. But that taught and still teaches me a lot. More than ever with Rust were you add deps via cargo and only use the public interface (mostly chaining methods again).

In conclusion, switching to Zig was a great decision. Plus, the community is hilarious. Really helpful and nice, even when discussing controversial topics like LLMs.

But of course, all only my personal experience. You could also go with both :wink:

13 Likes

It’s suboptimal decision. Learning effectiveness with LLM is higher. Just challenge and ask it to explain all stuff around generated code, why ownership has this shape, is it safe to copy this value, why it uses so many “@” builtins. Why it inserted “unreachable”. Why it uses std.c instead of existing stuff. Why it decided to use a particular data structure. All these points are great entries for your research of stdlib and it’s code. Don’t be passive learner, be a coach of LLM-dummy and learn faster yourself!

From my experience existing Zig materials don’t teach much besides language basics. Especially how to design data model, storage and ownership. To be fare it’s a tribal knowledge for all low-level langs.

LLM’s could really aid with designing of real apps. They are bad at it as humans but you could challenge it opposite to your dear handwritten code you have bias to.

2 Likes

I believe this (focusing on memory safety more than on “other bugs”) is a rational thing to do!

The main issue here is that “other bugs” can, worst-case, reduce utility of a given program to zero, while memory safety issues lead to negative utility, via compromising security.


A longer explanation follows:

As an example, suppose I downloaded an application for browsing funny memes from the internet. If the application is just buggy (crashes, leaks memory, is unreasonably slow, etc), I just don’t run it, and I am not worse off compared to an alternative world where this meme viewing software doesn’t exist.

Now suppose that the application is implemented in C and has memory safety issues. This sometimes means that the application can be exploited. For example, a carefully crafted adversarial meme can cause the application to read the data it wasn’t supposed to read, and send it to the attacker. In this world, opening the meme software could lead to my credit card number being stolen, or some such. The utility is negative — I am actively worse off compared to the world where the software just doesn’t exist.

A real world example of this effect are the recent Linux kernel vulnerabilities. My understanding is that they boil to basically this: There’s this kernel module, which is old, crufty, unused, and nobody cares about it existing at all. It could be completely broken! However, this module has an index-out-of-bounds, which allows malicious program to modify memory of unrelated programs. Suddenly, this module becomes very valuable to attackers, who can use it to take over Linux machines.

This negative utility reasoning I think justifies emphasizing memory safety in particular, via primum non nocere.


There are two questionable inferences there:

First, Is negative utility real? Do users actually suffer material damage from exploitable programs? I don’t know. There’s a lot of direct evidence of people caring about this, with CVEs and such, and with every juicy vulnerability making it into the news. As for direct damage, my understanding that there are some high profile targeted attacks (a journalist finding spyware on their phone), which are traceable to security issues somewhere. There’s also an issue of botnets from residential IPs (your smart toaster getting pwned and the like). Though, my understanding is that these days botnets are “legit” — there are certain "SDK"s you can integrate into your mobile application, and receive money every time a user opens your app.

Second, There’s a certain equivalence in the above between memory unsafely and security vulnerability, is it justified? Well, if you write your app in a garbage collected language, you generally get memory safety for free. You can still have XSS, SQL injection, etc, of course, but you are protected from vulnerabilities due to memory unsafely. And given that most software is written in GC languages, I think it’s fair to say memory safety doesn’t matter much in the grand scheme of things.

But of course this doesn’t apply if you are using a memory unsafe language! Here, there’s very believable, very robust number: you should expect more than half of security issues in C/C++ code to be attributed to memory unsafely. There were reports from all of Apple, Google, Mozilla and Microsoft, saying “yup, XX% of CVEs in our C++ code is memory unsafety”. This doesn’t mean that you can’t write secure C, but it does mean that security isn’t default outcome.

But note that these are findings for C/C++ code, not “average across not memory-safe languages”. And these two languages are famous for being quite adversarial when it comes to UB. If all that code was written in Zig, what would be the number of security vulns due to memory safety?

This is the question I genuinely don’t know the answer to. My current hypothesis is that the outcome would be approximately the same for ReleaseFast mode, and significantly, significantly better in ReleaseSafe. My anecdotal understanding is that the vast majority of “memory safety exploits” are downstream of out of bounds indexing, and that’s something Zig solves pretty conclusively in safe modes.

Though, I am confused here. My understanding is that both ghostty and bun are/were distributed in ReleaseFast form. I would expect that to be exploitable in theory, and exploited in practice, given how widely they are used.

11 Likes

The danger that memory corruption poses is real and I think we can all agree that it’s a class of bugs that is worth paying extra attention to, but the reason why it’s dangerous is because it lets you create weird machines, and in sufficiently complex software you can make a weird machine also without memory corruption. SQL injection, which you mentioned in your comment, is a great example of how that’s not just a theoretical argument.

Two Ghostty CVEs, no memory corruption (afaik), machine now allows arbitrary command execution nevertheless:

I would prefer people talked about how to avoid having their software turned into weird machines rather that to talk about that one way you can do that. But I would prefer even more if people talked about correctness as a whole.

Going back to my original point, I get it if somebody wants to put an extra accent on memory safety (and in general minimizing dangerous bugs right away rather than fixing them eventually), but my impression is that some people really got hit hard by a simplistic marketing message that essentially made them worse engineers without them realizing.

20 Likes

Ex-Rust programmer and long time C programmer here, so I feel like I’m well positioned to give a take!

How is the developer experience compared to Rust? (…) I’m wondering if it’s better to write your own web framework in Zig if it can reduce the complexity compared to Rust and tokio. (…)

Rust has a more polished developer experience, it has mature tooling, great error messages, more learning resources, but it is inherently a more complex language in both the surface level (the code you write) and in its internals.

This may be a bit tangential to your question, but I think it’s a valuable reflection to have.

Complexity in itself isn’t bad, but I have found that languages in the “sophisticated” school of thought tend to teach helplessness, they incentivize a thinking were you don’t have to worry about what’s under the hood because someone else smarter has already solved it for you—e.g. borrow checker, smart pointers, garbage collection allow you to not think about memory management, these are different approaches from someone architecting a solution.

You can see a reflection of this in how often Rust code pulls several a packages for every single little thing. This is largely worsened by the fact that when you code a solution in Rust, you aren’t just coding a solution, you have to code a solution that can be expressed within Rust’s safety semantics.

Now, I’m not saying this is bad and I moved on to Zig because of this, I believe there is a real value to Rust’s approach, and that will come down to what you prioritize.

There has been a similar contrast between C vs C++, where C is easier to learn, more predictable*, its semantics being closer to what the machine will do (not quite what you C is what you get, but closer) and C++ is a mistake more concerned with adding features that stops the user from making mistakes.

If it’s better—to write your own web framework in Zig or do Rust + tokio—will come largely down to your personal objectives and way of thinking.

My way of learning is to read source code from more experienced people, understand what I need and don’t need from it, then implement what I need, and I believe the “simple” school of thought makes that a lot easier, hence it helps avoiding learned helplessness!

Is the memory safety hype really such a big deal? Are there any ways we can reduce these vulnerabilities and what not with Zig?

It is a big deal, proving a program is memory safe is an amazing capability, but features don’t come for free and there is always a tradeoff. It’s also good to avoid one metric overtaking judgement (or sooner or later you will find yourself a Twitter influencer!), in gamedev we prioritize having low-level control and high iteration speed—which are the first ones to be sacrificed by the Rust compiler : ).

I believe TigerBeetle is a good case on how simplicity and iteration speed can make up for the lack of gran architect sophisticated solutions™.

And finally, are there any other resources I can use to learn Zig other than the standard reference handbook? I’m refusing to use any AI/LLM tools because, you know, I’m actually interested in learning this.

Ziglings looks really good, and https://zigbyexample.neocities.org/ looks good too. I can’t help much here as I’ve been programming for a long time, and I just learned Zig by picking a project, checking the documentation and looking at the source code for the standard library.

It’s a good instinct to avoid LLMs tools, but I believe they can be useful for leaning if you are conscious about it (which you seem to be), because they are great search tools as they are built on stolen data and can help you answer hard to search questions.

Much better than that is the Zig discord : ), or finding a study group, but unfortunately there are very few cultural structures incentivizing that.

12 Likes

From my experience with C even ReleaseFast is better due to slices. Loops over slices, sentinels allow to avoid a big chunk of usual C bugs. Optionals are another great thing. Instead of inventing special values you easily forget and violate in C you have a direct modeling tool.

7 Likes

I have been a professional web developer for almost 10 years now. As much as I love Zig, if your goal is web development, I would seriously consider looking at golang, if you haven’t already.

I also consider myself a polyglot, and have used quite a number of languages. Generally speaking, you can “learn” a language without committing to it, and any language worth its salt will teach you something valuable.

That being said, rust is the one language I gave up on for requiring too much from me- async + macros is a lot. I like lisp style macros and Zig’s comptime, because neither requires you to learn a whole separate “language” for them.

If you’re just starting out, it’s more valuable to learn data structures, how to do proper auth, use middleware, and other programming concepts that are not language dependent.

But hey, if rust floats your boat, then go for it! What ultimately matters is learning and growth, so whatever language excites you is the one to go for. Don’t get too bogged down with “committing” to any particular language, the others will still be there when you get bored :slight_smile:

P. S. Unless you’re doing LLM work, sqlite often works just fine rather than postgres.

4 Likes

Yeah, that’s an excellent point! I often wonder just how much less of a problem memory unsafely would have been if we did C’s Biggest Mistake - Digital Mars in C11.

2 Likes

If you wanna learn something, use zig. If you wanna build some web app real quick, use rust + llm.

Most of zig libs are small enough to learn, like the http.zig, it’s just about 10k line of zig code.

If you wanna learn something about tcp server developing, highly recommend this series from the author of http.zig. You can learn a lot from a single thread server to multi threads to thread pool to poll, epoll and kqueue.

2 Likes

Don’t use LLMs if you’re a student unless your dream is to grow up mediocre and lonely. It’s an isolating technology that deprives you of nuance, creativity, and rots your brain. The people suggesting this in this thread are deluded.

47 Likes

Many errors in a program can compromising security, memory corruption is just a subset thereof.

1 Like

Many errors in a program can compromising security, memory corruption is just a subset thereof.

I must say I am a little bit annoyed at this comment, because there’s a very explicitly quantified statement there:

Here, there’s very believable, very robust number: you should expect more than half of security issues in C/C++ code to be attributed to memory unsafely.

which itself is a part of 4-paragraph discussion of exactly this issue.

There’s a lot more to be said there, like kristoff data point that 100% of ghostty CVEs so far are not that, or baverman’s point that having slices might help even in ReleaseFast. Figuring out what’s going on there is super-useful, willfully forgetting what we do know already is not so much.

2 Likes

I’m sorry, I wrote this before reading your whole post, because as a head line, it felt wrong to me.. You explained it very well further down, as usual.

2 Likes
  • How is the developer experience compared to Rust?
    The developer experience with Zig is worse, and will be for a good while.
    With Rust you can probably get going running, while with Zig you will be accelerating from the starting-blocks. Zig has much less tooling, fewer established ‘just-go-to’ libraries, and the language along with its standard library isn’t ironed out. But what you get with Zig is a much leaner, less bloated modern language with drastically faster compile times, the mental model is smaller, and things stay exposed to you; no hidden control flow, allocations are not reached in the background, etc.
    And the fact that the standard library is not a science to read and understand unlike C++ and probably Rust, says more than something.
    Lastly one nice design goal of Zig is that code shouldn’t become “over-personalized” - the aim is to have one obvious way to do a thing (though Zig is loosening this somewhat in places, which shows it isn’t dogmatic about it) - this helps readability but can feel restrictive for some.

  • How does package management work in Zig?
    You can say Zig has a “weak package management” compared to the modern stuff, but this is deliberate. It is a way to not encourage clue-less dependency jumble.
    Fast version, every project has two files that work together: build.zig.zon and build.zig. The .zon part stands for Zig Object Notation - basically a Zig struct literal that acts as the manifest, listing your dependencies as a url plus a content hash.
    Side-by-side lives build.zig, the actual build script - written in Zig itself, not some YAML/TOML/Make hybrid. That’s where you pull the declared deps in as modules and wire them into your artifacts.

  • How is the future of Zig?
    As for the language, it’s not moving the most rapidly to completion, we haven’t reached “correctness” in the space where Zig wants to identify, which is fine since it’s very hard - async has been rebuilt a few times, the new I/O model is landing, non user-facing things are coming together, many things that are maturing (is my feeling).
    For myself I have always felt that I can trust where Zig is heading, the language developers are truly skilled while opinionated in healthy amounts.
    As for the community - this is just my impression - but it is smaller and doesn’t grow rapidly anymore, on the contrary my feeling has been that it has shrunk compared to some years ago, or at least that the ‘hype’ has cooled.
    Since Zig moved off Github (it lives on Codeberg now) I have felt that it has less ‘drive-by’ exposure, but I think this has been a good thing.
    A soft reset of sorts: less casual traffic, fewer low-effort issues, and the people who followed the move are the ones who actually wanted to be there.
    Those who have stayed with Zig are generally passionate about the language and see its potential to be one of the greatest tools for developers of great software.

  • Are there any resources I can use to learn Zig?
    Absolutely (search and you will find), and I would not omit using language models to assist you - just use them as something of a “rubber duck”, not as an authority.
    Just a heads up that for Zig in particular, since the language has changed so much, the model can fabricate confidently wrong code that looked right two versions ago.
    But the compiler is honestly one of your best teachers here - when it complains, it tends to complain precisely enough (but more in compiler-developer type terms), so let it correct yourself.

4 Likes

Point taken, on re-reading I also realize that my original phrasing was ambiguous – in my mind I have a Venn diagram where “other bugs” are disjoint from security issues by definition, but I haven’t communicated that!