Oh man this finishes too early, I would want to read more!
skrebbel•Aug 22, 2026
It got cancelled halfway
memco•Aug 22, 2026
Agreed.
There's this line:
> Wouldn’t it be cool if we could just use standard OS threads, blocking APIs, avoid new shinies like io_uring, but still get to cancel any work reliably?
Wish more was said about this: why would that be cool? I get that having robust cancellation in standard threads is cool, but why do we want to avoid io_uring?
LoganDark•Aug 22, 2026
> why do we want to avoid io_uring?
io_uring has been one of the greatest sources of exploits for the Linux kernel in years. io_uring has resulted in so many practical privilege escalation attacks that many containers completely block it, and companies like Google keep it entirely disabled. RHEL also ships a kernel without it by default.
lukaslalinsky•Aug 22, 2026
Programming asynchronous code is hard. Execution is split up, you have extra state machine to handle, extra resources to manage that need to survive across async boundaries. And by asynchronous, I mean either callbacks or manually checked completions from some event system. Modern languages hide that under async/await, which is much better from DX perspective, but still leads to split in the ecosystem, and it's hard to optimize across async boundaries.
This is an example why Go is such a successful language, in my view. It hides the async complexity and allows you to pretend you have a simple continuous thread of execution. It's just cheaper than system threads. Imagine if operating system threads and the blocking syscalls were this efficient.
I've spent the last year building a similar runtime for Zig. Purely because I want my applications to forget they are using things like io_uring in the background.
zuzululu•Aug 22, 2026
I'm shipping in Rust but any reason to do so in Zig ? What does it offer over Rust ? Something tangible benefit to end user or developer using ai assisted development ?
rahen•Aug 22, 2026
Use Rust if you're not writing code yourself.
The borrow checker will catch all kinds of bugs that AI-generated code will happily compile in Zig but will blow up as UB at runtime.
Zig's value prop is different and closer to a modern C: it fits in your head and maps fairly closely to assembly. There is no hidden control flow or hidden allocations, so you can tweak performance at a very low level. You're the pilot, not the compiler.
Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust.
eptcyka•Aug 22, 2026
> You're the pilot, not the compiler.
This to me reads like an LLMism.
solatic•Aug 22, 2026
> The borrow checker will catch all kinds of bugs that AI-generated code will happily compile in Zig but will blow up as UB at runtime.
This has not been my experience; Claude does a great job of writing unit tests for the Zig code, and combined with Zig's fuzzing features and a Python-based integration testing suite, I have avoided hitting runtime UB so far. In exchange, I get much faster compile times, which are important for the agentic development loop.
zuzululu•Aug 22, 2026
Can LLMs not write Zig code ? I'm not really understanding your explanation for why we can write other languages with LLM but not Zig here.
> Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust.
Not really seeing the connection here. What do you mean by code artisan? Are you trying to gatekeep Zig because you think Zig is too difficult for LLMs?
rahen•Aug 22, 2026
You asked if there was "tangible benefit to end user or developer using ai assisted development". My answer is no, it can be done but has no benefits for this use case. Use Rust here, because its compiler acts as an AI safety net.
Being a code artisan is not gatekeeping. It means if you're used to being close to the metal and sometimes know better than the compiler, Zig is for you. If you're not, use Rust.
9dev•Aug 22, 2026
> if you […] often know better than the compiler
With all due respect, that tickles my spidey senses. People claiming to know better than a compiler about low-level details of their code are most often either engaging in premature hyper-optimisation, or suffer a specific kind of greybeard hubris IMHO
applfanboysbgon•Aug 22, 2026
The idea that humans can't solve a specific problem more efficiently than a generalised algorithm that has to work for all code ever written in the language is a lie that JS script kiddies tell themselves to justify remaining ignorant without feeling bad about it.
9dev•Aug 22, 2026
Oh, humans can definitely do that, in some capacity, if they're attentive, slept enough, aren't hungry, or in emotional distress, for a limited amount of time.
A generalised algorithm can do this consistently, billions of times, which happens to be the amount of problems involved in building an application.
applfanboysbgon•Aug 22, 2026
Which is why we don't write entire programs in raw assembly, but that doesn't mean it's actually difficult to do better than a compiler. You focus your efforts on where benchmarking and profiling tell you your bottlenecks are in your hot paths. If you actually engage in this in a regular basis, you will recognise that despite the myth-building and fear around writing low-level code, compilers do "stupid" inefficient stuff all the time, and it's not hard to do better than them with the specific context of your project in mind.
zbentley•Aug 22, 2026
Sometimes, but measure the number of people like that against the massive number of people who blow their whole leg off by trying to second-guess the compiler. If I had a nickel for every “performance critical” (which it never is) weird bullshit thing I’ve seen people do to “defeat” (really: totally misunderstand) a compiler behavior, which instead resulted in severe bugs, I’d have a lot of nickels.
The overlap of situations where compiler-second-guessing truly being necessary and the programmers present are capable enough to implement it is narrow enough that I’m fine with most languages’ escape hatches being similarly narrow.
lowbloodsugar•Aug 22, 2026
I mean, using Rust or Zig rather than typescript, go, Java or C# is often a premature optimization, depending on use case. Plenty of games where majority of code is C# or unrealscript. Most people I talk to are surprised that Java has monomorphisation at runtime.
Of course I’d rather be writing the engine. =)
norir•Aug 22, 2026
This reads as rather dismissive and not so humble. Compilers generating suboptimal and sometimes broken code very slowly is the norm, not the exception. Whether or not it's worth worrying about is indeed a development tradeoff but not one that should be so casually dismissed.
zuzululu•Aug 22, 2026
> Being a code artisan is not gatekeeping. It means if you're used to being close to the metal and often know better than the compiler, Zig is for you. If you're not, use Rust.
You are saying that if you are not a code artisan (who by definition can't use LLM) likeyou then they should not use Zig. Honestly, I don't care. I'm not a code artisan, if Zig can help me ship faster and better with LLMs, my job is done and that's what I get paid for.
> Codex CLI taking over 15 minutes to recompile on my fairly high-end machine. Zig's incremental compilation optimizations are amazing, giving near-instant recompiles measured in ms instead of minutes.
So there is a benefit here mentioned by the non-arisans which is what I wanted to know but you wouldn't know if you don't use ai assisted delivery.
mohamedattahri•Aug 22, 2026
Nobody's writing Zig because they think they can beat the Rust compiler.
Comparisons to Rust usually stop at memory safety and overlook what no-hidden-control-flow buys you when it's applied consistently across the whole language.
The same mechanism that lets you control allocation (passing an allocator) extends to I/O. For instance, writing Zig, I know exactly when I'm handing control to the kernel and when I'm not. In the vast majority of languages, it's something you'd observe at runtime, whereas in Zig, it's simply the source code you compiled.
So the point of writing Zig over any other language isn't beating the compiler, it's understanding and controlling what your program does at any given moment.
je42•Aug 22, 2026
So far claude has been fine to generated zig code. Dont have lots of issues. Tijy local models have more problems with zig, need additional instructions.
In general, what helps is to instruct ai to use test coverage to ensure the cover all edge cases with tests.
Ygg2•Aug 22, 2026
Use Rust if you want to write in a memory safe, high performance language.
> Zig's value prop is different and closer to a modern C: it fits in your head and it maps fairly closely to assembly.
This can't be correct for the simple reason that it has both a modern optimizing compiler (LLVM) and UB.
A modern compiler will try to autovectorize your code, so you don't really know what the assembly will be.
UB gives compiler license to rewrite your code however it sees fit.
lowbloodsugar•Aug 22, 2026
> A modern compiler will try to autovectorize your code, so you don't really know what the assembly will be.
Looking at what the compiler actually did is an ancient tradition. I’ve even done it with Java. Seeing five virtual calls with bounds checking all over get turned into a single load instruction has to be seen to be believed.
bsaul•Aug 22, 2026
it's also my opinion. Which makes me wonder : isn't there an opportunity to create a variant of rust that would make absolutely zero compromise on UB and safety at the detriment of user experience ( which we don't care about now, with AI generating the code) ?
Like programming in a kind of super strict IL. Or the opposite : super poweful, super abstract language, yet extremely strict.
flohofwoe•Aug 22, 2026
LLMs are actually pretty good at finding potential memory corruption issues in unsafe langauges upfront, to a point where I wonder if it even still makes sense using Rust with its slow compile-edit-test loop in a fully automated code generation scenario.
ModernMech•Aug 22, 2026
Part of the reason the compile-edit-test loop is slower than in other languages is because Rust is doing a whole borrow checking phase other languages don't. I don't see why it'd be faster or more accurate to get an LLM to do the same static analysis as the Rust compiler. Although I'd be interested in an analysis of how much each would cost in dollars.
bombela•Aug 22, 2026
It's the compilation that is slow, not the checking. You can observe this by comparing "cargo check" and "cargo build".
lowbloodsugar•Aug 22, 2026
I’ve shipped games written entirely in assembly. I now work on a large service you have heard of. I graduated manga cum laude. I’m not smart enough to write systems in C or Zig that don’t have bugs.
The question I ask myself is “would I write a game in Rust?” Zig seems like a better fit: you can be clever without being chided by the borrow checker. But as a “code artisan”, there’s an interesting challenge in making it work with Rust.
I might use Zig on a project if it was just me. I wouldn’t use it with the a team that I didn’t hand pick.
Smart people like Zig. Smart people like Rust. Smart people like LLMs. It’s a big Venn diagram. It be great if we could not bash each other.
applfanboysbgon•Aug 22, 2026
I often use LLMs to build and modify open-source tools for personal use and Rust's compile times are disgusting, eg. Codex CLI taking over 15 minutes to recompile on my fairly high-end machine. Zig's incremental compilation optimizations are amazing, giving near-instant recompiles measured in ms instead of minutes. I would certainly classify four orders of magnitude faster compilation as a tangible benefit even if you're not writing the code by hand.
zuzululu•Aug 22, 2026
Rust is quite slow but that is an interesting benefit but still not sure what the trade offs are, Rust has a huge mature ecosystem and there are lot of jobs for it.
Are you able to ship faster with Zig vs Rust? How did you arrive at the 4x figure?
I'm really puzzled why people are so angry over using ai assistance with Zig. LLMs are always going to be able to write better code faster and better than anyone who calls themselves code artisans in this day and age.
I think this comment posted a while back someone who worked on Zig is pretty telling:
> The key problem with Zig nowadays is how much of its community and adoption is driven by anti-Rust sentiment. As a result, while Rust puts beginner onboarding and documentation at the center of its culture, as opposed to the “C neckbeard”'s culture, Zig is going the other way around.
And ultimately this didn't stop people from using AI generating Zig code as much of the users in the thread are already using it to ship quality faster.
Happy to use the work the community outputs and culture is largely irrelevant when prompting LLMs outputs code that doesn't really require any intimate knowledge with the syntaxes
hiccuphippo•Aug 22, 2026
Zig lets you be very explicit about what you want. Zig's hello world takes 3 or 4 lines where other languages take 1. That is how much other languages make decisions for you. Some people care to make those decisions themselves.
applfanboysbgon•Aug 22, 2026
This is the weirdest basis for comparing a language I've ever seen. Zig is one line as well, `std.debug.print("Hello, world!\n", .{});`, unless you're counting defining main and its brackets as 4 lines, in which case... Rust has that too, Java is 7 lines and C# is 8 lines to import System library and define the Program class as well if you're not using top-level statements / implicit usings.
---
Edit for replies complaining I used debug.print:
Okay, `try std.io.getStdOut().writer().print("Hello, world!\n", .{});`. Still one line, more explicit with chained methods, but that still just goes to show you how arbitrary this metric is -- Zig's standard library makes you be more explicit with one function, but it doesn't make you be as explicit with another one that works essentially the same way but writes to a different stream, ergo this has nothing to do with the language's inherent explicitness but rather comparing the implementation of a single random function.
solatic•Aug 22, 2026
std.debug.print is, as its name suggests, for debug output, not for program output.
In Zig, you create a buffered writer for the stdout file handle, write hello world to the buffer, and then flush it. It exposes what's actually happening underneath.
denismenace•Aug 22, 2026
As the name suggest `std.debug.print` is a short hand for debug printing. In a CLI app for example you should use IO.
ErenayDev•Aug 22, 2026
(reply to edit)
small typo fix:
instead of `std.io`, it should be `init.io`. `init` is first parameter in `main` function.
zuzululu•Aug 22, 2026
As does C++ and other languages. What is so special about Zig that you cannot use LLMs with it? Please provide examples.
caspper69•Aug 22, 2026
The breaking changes version to version. Zig tends to be quite liberal about moving forward, as should be expected at its version level. It simply outpaces the llms datasets.
ErenayDev•Aug 22, 2026
Zig's compiler somehow feels lightweight to me compared to Rust's. When i develop something in Rust, the compiler and LSP is overheating my CPU. So im using Zig nowodays for long life my laptop.
When I had problems in my Zig codebase(latest version), the LLM cant resolve my problem. It kept giving me results based on older versions of the Zig code. This was due to breaking changes in every version. Thats why I no longer ask the LLM for help with Zig-related code. The folks on Zig Discord server and its forum, helps me very much.
pyrolistical•Aug 22, 2026
Give it agent instructions in the major breaking api changes. I force around Io stuff. Then point it to the zig source code.
Sure it wastes a bit of time always figure it out when it fails to compile.
This is why I’m excited to see qwen3.8 27b removed a bunch of knowledge for more reasoning. Baked in old zig api is worthless
phplovesong•Aug 22, 2026
I know syntax does not REALLY matter, but Zig is just kind of subpar syntax wise. Its really verbose and picked weirdly from what already exists. Zig code is usually hard to read because it really noicy, and has weird things not existing in other languages without merit.
pzittlau•Aug 22, 2026
I don't think that it's really subpar. It's just unusual compared to others. In and of itself it's very consistent. For instance there's `|capture|` for capturing all sort of things(errors, optionals, ...) in nearly all control flow constructs. `blk:` for naming blocks, `if`s, `switch`, and so on.
Have a look at this blog post:
https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html
phplovesong•Aug 22, 2026
I saw that article previously. Nearly all of the syntax seem to be in-house with little benefit. All the examples could just use some modern c-like thing.
Zig has benefits, like comptime, no hidden control flow, memory mngmt, cross compilation etc. But its syntax is just a mouthfull of wats, whys and wtfs.
I can forsee a compile to Zig languge popping up sometime soon.
ulbu•Aug 22, 2026
|capture| hides an inconsistency that bugs me – everywhere else, assignment to a variable flows leftwards. |capture| is an unnatural rightwards assignment.
in general, I like zig syntax, but i find that it had very little regard to how the eye moves on the page. it’s jarring at times.
simjnd•Aug 22, 2026
But the capture is conditional so it makes sense.
if (evaluation) result = evaluation
if (evaluation) |result|
Although assignments as expressions in C are convenient, I don't think they make a ton of sense and find Zig's capture easier to read (easier to immediately see what's being evaluated)
ulbu•Aug 22, 2026
if |result| (evaluation)
simjnd•Aug 22, 2026
I think you could argue for it both ways. Then you could claim ternaries are inconsistent too, shouldn't it be:
resultA : resultB ? (evaluation)
if we always put result first?
I think the most important piece of if statements and ternaries is the condition being evaluated and it's worth putting that first?
ulbu•Aug 22, 2026
but zig has no ternaries, so it does not apply to a discussion about zig’s syntax.
and ternary is a branch with no variable introduction, so it doesn’t apply again.
(it’s basically a weak switch expression, and the value moves leftwards towards its invocation.)
nromiun•Aug 22, 2026
Of course syntax matters in any programming language. That is like saying the alphabet and grammar does not really matter in English.
zuzululu•Aug 22, 2026
with LLMs? syntax doesn't really matter anymore exactly because of what you mentioned in your last sentence.
ModernMech•Aug 22, 2026
With LLMs you pay per token, so if you can express the same code in 1 / 10th the tokens that absolutely matters. Moreover they have a finite context window, so more concise syntax can make that more economical.
zuzululu•Aug 22, 2026
Sure but how many devs can sustain that level of efficiency around the clock and how much thought do you think their employers will give when the LLM tokens pay 1/100~1/1000th of the wage paid
ModernMech•Aug 22, 2026
Wdym, the LLM is writing it either way? My point is all else being equal, you’d prefer the code that’s shorter for the reasons stated.
zuzululu•Aug 22, 2026
I want code that is efficient, secure and cheap to produce. There is no way a human can compete with a network of agents doing that. Whatever edge you think exists is on a downward trend. Look at where we were in the days of GPT 4o vs now in terms of coding capability. Look at the marketplace for overseas contractors and the impact AI has had.
To ship what I do now would've cost a few million dollars per year in terms of the team needed to maintain it now its 1000x cheaper
ModernMech•Aug 22, 2026
I'm not making that argument are you responding to the right person?
My argument was that syntax still matters because LLMs communicate in syntax, and they pay for that per token, therefore LLMs make syntax more relevent as you can actually calculate cost to write in one language versus another.
I'm not arguing that humans can compete with a network of agents.
kryptiskt•Aug 22, 2026
Some people are actually interested in programming, coming and bleating about LLMs making all the finer points of it unimportant is as clueless as a manager coming here and telling us that syntax is unimportant because he has programmers for that crap.
If you don't care, don't go around in programming threads telling you how it doesn't matter anymore. It doesn't matter to you, because you prefer to be ignorant about the details of programming, and you have found tools that let you live in ignorance, good for you. But some of us do care, and are going to continue to do so.
zuzululu•Aug 22, 2026
My point isn't that what you are doing is pointless or that you shouldn't enjoy what you do but that it ultimately holds very little economic value especially as someone in charge of hiring developers, their experience is more valuable in the sphere of architectural design than expertise over syntax.
LLMs compile english to whatever code you want and it can write it better, faster and more efficiently than a human can over the long run. You might have an edge in shorter sprints but that gap is quickly reduced when LLMs simply learn and apply whatever optimization they find and it can continue to output without any diminishing returns and at fraction of what it takes to pay a human to do it.
fishgoesblub•Aug 22, 2026
It does if you actually want to understand what the slop-bot is doing.
flohofwoe•Aug 22, 2026
Well, compared to what? Zig is much nicer to read than Rust or C++, about the same as Typescript, but not as nice as modern C.
But that's just my opinion.
Such questions usually come down to "how familiar am I with this programming language", and anything that doesn't look like your pet language looks ugly. Except Rust and C++ of course, those are objectively ugly ;P
phplovesong•Aug 22, 2026
Ofc it boils down to familiarity. But making a custom version of, say structs is just a weird design. The mainstream struct syntax is something everyone knows, and zig made all kinds of weird decisions around it. Same goes for @SpecialThing, looks like PHP to me. Multiline strings are also a weird addition. The list goes on.
flohofwoe•Aug 22, 2026
> But making a custom version of, say structs is just a weird design.
This I don't understand? Zig structs are pretty much the same as in any other language, except that the declaration can be more flexible by building the struct type via comptime code (e.g. how Zig does generics) - and Zig groups structs and namespaces under the same keyword (which hardly matters in practice though).
> @SpecialThing
...not any weirder than `__builtin` keywords in Clang or GCC and at least in Zig it's obvious that anything starting with a `@` is a builtin, while in Clang/GCC the `__` is not explicitly reserved for builtins. ObjC also uses a leading `@` to separate ObjC keywords from regular C keywords. Agreed that the @-noise can get a bit excessive in Zig though (mainly because implicit casting is heavily restricted, at least compared to C).
> Multiline strings are also a weird addition
AFAIK the 'weird' multiline syntax is for keeping the parser simple and fast. Multi-line-strings themselves are a good feature to have though.
In general, if Zig code starts to look too 'noisy', that's usually a sign that the code should be simplified.
I definitely don't agree with all design decisions in Zig, but the syntax is mostly fine (my main critique points are that Zig often tries to lean too much into 'design purity' than 'programmer convenience' and that parts of the stdlib are too 'object oriented'.
Twey•Aug 22, 2026
> in Clang/GCC the `__` is not explicitly reserved for builtins
In fact in C identifiers starting with _ are reserved for the implementation (except for in local scope if the second character is not an underscore or capital letter).
rjzzleep•Aug 22, 2026
Early Rust was a lot more readable as well. Somehow it turned into the perl 6 of systems languages. They crammed everything they could in there.
jjgreen•Aug 22, 2026
Favorite comment of the day; you do know it will get downvoted to crap right?
rjzzleep•Aug 22, 2026
Maybe I'm living in my own bubble, but I feel like criticizing Rust has become a little more acceptable recently.
mkeeter•Aug 22, 2026
Probably because this is a post about Zig’s threaded IO, and complaints about Rust syntax is two conversational leaps away from that subject!
panzi•Aug 22, 2026
Early Rust had ~ and @ references.
a2ff6eeb0•Aug 22, 2026
Which, IMO, read nicer than words and ::s drowning out names.
allthetime•Aug 22, 2026
Custom syntax highlighting / theming to emphasize names vs. qualifiers is very helpful.
panzi•Aug 22, 2026
I'm not really against such special symbols, only if they are too much, like in Perl.
~ and @ weren't replaced by anything with ::, though, ~Foo is Box<Foo> and @Foo is Rc<Foo> (or is it Arc<Foo>?). :: to access a member of a module already existed when ~ and @ was in Rust.
andrepd•Aug 22, 2026
Weird thing to say when early Rust had sigils everywhere.
All my days of low level stuff were in the windows world where async/cancel was supported since nt kernel days at least. Wrapping this coherently at some level of abstraction was always worth doing, although threads are just one way. Overlapped I/O let you do it all on one thread. Linux looks harder.
Great that Zig is supporting this more “first class”; not strictly required, but looks useful.
lukaslalinsky•Aug 22, 2026
If you are comparing to overlapped I/O, you should use io_uring as reference and cancellation in io_uring is fairly simple.
_old_dude_•Aug 22, 2026
Just here to say that Java as interruptible channels since the beginning of 2000.
You can interrupt a blocking IO operation with either interrupt() or close().
You might want to read the “prior art” section of their article…
embedding-shape•Aug 22, 2026
Who's right though? The article seems to go directly against what parent said above?
> In Java, there’s a similarly looking thread interruption mechanism. Critically, it doesn’t support interrupting syscalls: IOException and InterruptedException are both checked and unrelated, meaning that IOing functions are not interruptible
One says IOing functions are not interruptible, other says "You can interrupt a blocking IO operation" :)
Sharlin•Aug 22, 2026
The article seems to talk about how `Thread.interrupt` works with synchronous IO, rather than the async IO machinery of `java.nio`. So I'd say the article is inaccurate or at least incomplete.
lowbloodsugar•Aug 22, 2026
NIO can be blocking or non-blocking. Indeed you can switch between the two on a single channel.
twic•Aug 22, 2026
> IOException and InterruptedException are both checked and unrelated
Pretty sure you've been able to interrupt a thread blocked on IO in a normal InputStream since 1.0.2 in 1996.
There is a significant caveat to this, which is that if the underlying blocking IO operation isn't natively cancellable (and the JDK doesn't use the trick Zig uses here), then the interrupt is allowed to close the IO resource as a way of ending the operation early. In practice this is usually fine, as you're interrupting the thread precisely because you want it to give up on whatever it's doing, but it precludes some particularly subtle possible IO designs.
Not sure if this changes under virtual threads, where the thread is much more loosely coupled to the syscall.
tombert•Aug 22, 2026
I know some people hate on it, but I genuinely think that NIO is pretty good just in general.
It actually kind of annoys me; I feel like most Java code I've had to debug/maintain is slow and terrible because most Java engineers lack any ambition so they write the old terrible IO that they learned in university, and for years I guess I kind of erroneously assumed that Java was "bad" at doing IO.
Then I read a book on NIO, started writing my own code with channels and selectors and realized that it actually works quite well, and I found it relatively intuitive and performance was pretty solid.
This is actually a recurring pattern I've found in the Java world; Java has added a lot of great features over the years that make the language more ergonomic and performant and fun to write, but due to its prevalence in the "Enterprise" world and university, it selection biases towards people who refuse to learn anything new, meaning that a lot (the majority?) of Java code feels like it was written in 1997.
I have been writing a lot of Java in my free time, unapologetically using Java 17, 21, and 25 features, and I am actually enjoying it.
lowbloodsugar•Aug 22, 2026
Run with the options to dump optimized code to a file. Look at what it’s actually generating for all the byte buffer calls and you’ll see it’s piss-takingly fast. Looking at the Java it shows up as five virtual calls and a bunch of bounds checks. The JIT will turn that into a single x86 instruction in most cases.
inglor•Aug 22, 2026
Cool writeup but... Signals are not some opaque or roundabout feature to do this. Signals are a thing for a reason and this is how it's implemented in any threaded I/O library I've read.
eptcyka•Aug 22, 2026
Ye, but signals are cumbersome and a foot gun. Should a library ever install signal handlers? What about languages with runtimes? Ever read the spec on how go handles signals differently depending on how it is compiled?
Asmod4n•Aug 22, 2026
how do they handle that malloc aint async signal safe?
comex•Aug 22, 2026
You don’t have to do any significant work within the signal handler itself. In fact, the signal handler can literally be empty. What matters is that as long as SA_RESTART is not set, after the signal handler runs, the interrupted syscall fails with errno set to EINTR. Then the code that did the syscall can check whether a cancellation occurred (and retry the syscall if not).
Disclaimer: I haven’t looked at Zig’s implementation; I’m only going off how the Unix APIs work.
up2isomorphism•Aug 22, 2026
Just use C, these are well understood things 20 years ago.
7 Comments
There's this line:
> Wouldn’t it be cool if we could just use standard OS threads, blocking APIs, avoid new shinies like io_uring, but still get to cancel any work reliably?
Wish more was said about this: why would that be cool? I get that having robust cancellation in standard threads is cool, but why do we want to avoid io_uring?
io_uring has been one of the greatest sources of exploits for the Linux kernel in years. io_uring has resulted in so many practical privilege escalation attacks that many containers completely block it, and companies like Google keep it entirely disabled. RHEL also ships a kernel without it by default.
This is an example why Go is such a successful language, in my view. It hides the async complexity and allows you to pretend you have a simple continuous thread of execution. It's just cheaper than system threads. Imagine if operating system threads and the blocking syscalls were this efficient.
I've spent the last year building a similar runtime for Zig. Purely because I want my applications to forget they are using things like io_uring in the background.
The borrow checker will catch all kinds of bugs that AI-generated code will happily compile in Zig but will blow up as UB at runtime.
Zig's value prop is different and closer to a modern C: it fits in your head and maps fairly closely to assembly. There is no hidden control flow or hidden allocations, so you can tweak performance at a very low level. You're the pilot, not the compiler.
Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust.
This to me reads like an LLMism.
This has not been my experience; Claude does a great job of writing unit tests for the Zig code, and combined with Zig's fuzzing features and a Python-based integration testing suite, I have avoided hitting runtime UB so far. In exchange, I get much faster compile times, which are important for the agentic development loop.
> Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust.
Not really seeing the connection here. What do you mean by code artisan? Are you trying to gatekeep Zig because you think Zig is too difficult for LLMs?
Being a code artisan is not gatekeeping. It means if you're used to being close to the metal and sometimes know better than the compiler, Zig is for you. If you're not, use Rust.
With all due respect, that tickles my spidey senses. People claiming to know better than a compiler about low-level details of their code are most often either engaging in premature hyper-optimisation, or suffer a specific kind of greybeard hubris IMHO
A generalised algorithm can do this consistently, billions of times, which happens to be the amount of problems involved in building an application.
The overlap of situations where compiler-second-guessing truly being necessary and the programmers present are capable enough to implement it is narrow enough that I’m fine with most languages’ escape hatches being similarly narrow.
Of course I’d rather be writing the engine. =)
You are saying that if you are not a code artisan (who by definition can't use LLM) likeyou then they should not use Zig. Honestly, I don't care. I'm not a code artisan, if Zig can help me ship faster and better with LLMs, my job is done and that's what I get paid for.
> Codex CLI taking over 15 minutes to recompile on my fairly high-end machine. Zig's incremental compilation optimizations are amazing, giving near-instant recompiles measured in ms instead of minutes.
So there is a benefit here mentioned by the non-arisans which is what I wanted to know but you wouldn't know if you don't use ai assisted delivery.
Comparisons to Rust usually stop at memory safety and overlook what no-hidden-control-flow buys you when it's applied consistently across the whole language.
The same mechanism that lets you control allocation (passing an allocator) extends to I/O. For instance, writing Zig, I know exactly when I'm handing control to the kernel and when I'm not. In the vast majority of languages, it's something you'd observe at runtime, whereas in Zig, it's simply the source code you compiled.
So the point of writing Zig over any other language isn't beating the compiler, it's understanding and controlling what your program does at any given moment.
In general, what helps is to instruct ai to use test coverage to ensure the cover all edge cases with tests.
> Zig's value prop is different and closer to a modern C: it fits in your head and it maps fairly closely to assembly.
This can't be correct for the simple reason that it has both a modern optimizing compiler (LLVM) and UB.
A modern compiler will try to autovectorize your code, so you don't really know what the assembly will be.
UB gives compiler license to rewrite your code however it sees fit.
Looking at what the compiler actually did is an ancient tradition. I’ve even done it with Java. Seeing five virtual calls with bounds checking all over get turned into a single load instruction has to be seen to be believed.
Like programming in a kind of super strict IL. Or the opposite : super poweful, super abstract language, yet extremely strict.
The question I ask myself is “would I write a game in Rust?” Zig seems like a better fit: you can be clever without being chided by the borrow checker. But as a “code artisan”, there’s an interesting challenge in making it work with Rust.
I might use Zig on a project if it was just me. I wouldn’t use it with the a team that I didn’t hand pick.
Smart people like Zig. Smart people like Rust. Smart people like LLMs. It’s a big Venn diagram. It be great if we could not bash each other.
Are you able to ship faster with Zig vs Rust? How did you arrive at the 4x figure?
I'm really puzzled why people are so angry over using ai assistance with Zig. LLMs are always going to be able to write better code faster and better than anyone who calls themselves code artisans in this day and age.
I think this comment posted a while back someone who worked on Zig is pretty telling:
> The key problem with Zig nowadays is how much of its community and adoption is driven by anti-Rust sentiment. As a result, while Rust puts beginner onboarding and documentation at the center of its culture, as opposed to the “C neckbeard”'s culture, Zig is going the other way around.
And ultimately this didn't stop people from using AI generating Zig code as much of the users in the thread are already using it to ship quality faster.
Happy to use the work the community outputs and culture is largely irrelevant when prompting LLMs outputs code that doesn't really require any intimate knowledge with the syntaxes
---
Edit for replies complaining I used debug.print:
Okay, `try std.io.getStdOut().writer().print("Hello, world!\n", .{});`. Still one line, more explicit with chained methods, but that still just goes to show you how arbitrary this metric is -- Zig's standard library makes you be more explicit with one function, but it doesn't make you be as explicit with another one that works essentially the same way but writes to a different stream, ergo this has nothing to do with the language's inherent explicitness but rather comparing the implementation of a single random function.
In Zig, you create a buffered writer for the stdout file handle, write hello world to the buffer, and then flush it. It exposes what's actually happening underneath.
small typo fix:
instead of `std.io`, it should be `init.io`. `init` is first parameter in `main` function.
When I had problems in my Zig codebase(latest version), the LLM cant resolve my problem. It kept giving me results based on older versions of the Zig code. This was due to breaking changes in every version. Thats why I no longer ask the LLM for help with Zig-related code. The folks on Zig Discord server and its forum, helps me very much.
Sure it wastes a bit of time always figure it out when it fails to compile.
This is why I’m excited to see qwen3.8 27b removed a bunch of knowledge for more reasoning. Baked in old zig api is worthless
Zig has benefits, like comptime, no hidden control flow, memory mngmt, cross compilation etc. But its syntax is just a mouthfull of wats, whys and wtfs.
I can forsee a compile to Zig languge popping up sometime soon.
in general, I like zig syntax, but i find that it had very little regard to how the eye moves on the page. it’s jarring at times.
if (evaluation) result = evaluation
if (evaluation) |result|
Although assignments as expressions in C are convenient, I don't think they make a ton of sense and find Zig's capture easier to read (easier to immediately see what's being evaluated)
resultA : resultB ? (evaluation)
if we always put result first?
I think the most important piece of if statements and ternaries is the condition being evaluated and it's worth putting that first?
and ternary is a branch with no variable introduction, so it doesn’t apply again.
(it’s basically a weak switch expression, and the value moves leftwards towards its invocation.)
To ship what I do now would've cost a few million dollars per year in terms of the team needed to maintain it now its 1000x cheaper
My argument was that syntax still matters because LLMs communicate in syntax, and they pay for that per token, therefore LLMs make syntax more relevent as you can actually calculate cost to write in one language versus another.
I'm not arguing that humans can compete with a network of agents.
If you don't care, don't go around in programming threads telling you how it doesn't matter anymore. It doesn't matter to you, because you prefer to be ignorant about the details of programming, and you have found tools that let you live in ignorance, good for you. But some of us do care, and are going to continue to do so.
LLMs compile english to whatever code you want and it can write it better, faster and more efficiently than a human can over the long run. You might have an edge in shorter sprints but that gap is quickly reduced when LLMs simply learn and apply whatever optimization they find and it can continue to output without any diminishing returns and at fraction of what it takes to pay a human to do it.
But that's just my opinion.
Such questions usually come down to "how familiar am I with this programming language", and anything that doesn't look like your pet language looks ugly. Except Rust and C++ of course, those are objectively ugly ;P
This I don't understand? Zig structs are pretty much the same as in any other language, except that the declaration can be more flexible by building the struct type via comptime code (e.g. how Zig does generics) - and Zig groups structs and namespaces under the same keyword (which hardly matters in practice though).
> @SpecialThing
...not any weirder than `__builtin` keywords in Clang or GCC and at least in Zig it's obvious that anything starting with a `@` is a builtin, while in Clang/GCC the `__` is not explicitly reserved for builtins. ObjC also uses a leading `@` to separate ObjC keywords from regular C keywords. Agreed that the @-noise can get a bit excessive in Zig though (mainly because implicit casting is heavily restricted, at least compared to C).
> Multiline strings are also a weird addition
AFAIK the 'weird' multiline syntax is for keeping the parser simple and fast. Multi-line-strings themselves are a good feature to have though.
In general, if Zig code starts to look too 'noisy', that's usually a sign that the code should be simplified.
I definitely don't agree with all design decisions in Zig, but the syntax is mostly fine (my main critique points are that Zig often tries to lean too much into 'design purity' than 'programmer convenience' and that parts of the stdlib are too 'object oriented'.
In fact in C identifiers starting with _ are reserved for the implementation (except for in local scope if the second character is not an underscore or capital letter).
~ and @ weren't replaced by anything with ::, though, ~Foo is Box<Foo> and @Foo is Rc<Foo> (or is it Arc<Foo>?). :: to access a member of a module already existed when ~ and @ was in Rust.
Great that Zig is supporting this more “first class”; not strictly required, but looks useful.
You can interrupt a blocking IO operation with either interrupt() or close().
https://docs.oracle.com/en/java/javase/25/docs/api/java.base...
> In Java, there’s a similarly looking thread interruption mechanism. Critically, it doesn’t support interrupting syscalls: IOException and InterruptedException are both checked and unrelated, meaning that IOing functions are not interruptible
One says IOing functions are not interruptible, other says "You can interrupt a blocking IO operation" :)
https://docs.oracle.com/en/java/javase/25/docs/api/java.base...
The article just references Thread.interrupt
There is a significant caveat to this, which is that if the underlying blocking IO operation isn't natively cancellable (and the JDK doesn't use the trick Zig uses here), then the interrupt is allowed to close the IO resource as a way of ending the operation early. In practice this is usually fine, as you're interrupting the thread precisely because you want it to give up on whatever it's doing, but it precludes some particularly subtle possible IO designs.
Not sure if this changes under virtual threads, where the thread is much more loosely coupled to the syscall.
It actually kind of annoys me; I feel like most Java code I've had to debug/maintain is slow and terrible because most Java engineers lack any ambition so they write the old terrible IO that they learned in university, and for years I guess I kind of erroneously assumed that Java was "bad" at doing IO.
Then I read a book on NIO, started writing my own code with channels and selectors and realized that it actually works quite well, and I found it relatively intuitive and performance was pretty solid.
This is actually a recurring pattern I've found in the Java world; Java has added a lot of great features over the years that make the language more ergonomic and performant and fun to write, but due to its prevalence in the "Enterprise" world and university, it selection biases towards people who refuse to learn anything new, meaning that a lot (the majority?) of Java code feels like it was written in 1997.
I have been writing a lot of Java in my free time, unapologetically using Java 17, 21, and 25 features, and I am actually enjoying it.
Disclaimer: I haven’t looked at Zig’s implementation; I’m only going off how the Unix APIs work.