I'm too dumb for Zig's new IO interface
112 comments
·August 23, 2025latch
dchest
Ha, "Don't Forget to Flush" https://www.youtube.com/watch?v=f30PceqQWko
hardwaresofton
I'm not a Zig PM but the first obvious fix for the issues the OP wrote about is to write better documentation, including usage examples (the more the better, almost to a fault). Also doubles as a good time to reflect on whether the user is having to do too much.
If the tradeoff was absolute performance/avoiding introducing load-bearing performance-lowering abstraction I think that goal was achieved, but DX may have gone out the window.
brabel
You’re not familiar with Zig’s culture, I guess. Complain about the lack of documentation and be prepared for the flood of “just read the stdlib code” helpful comments by pretty much everyone who writes Zig right now. Because most APIs are just as hard to use as in this post (check things like HTTP and even basic file system operations) only the strongest survive.
virtualritz
I do not think this is a viable excuse any more.
I am just editing docs now that Claude Code writes for me. I am fanatic about developer docs (and I guess an exception as I love writing them) but with a set of concise instructions for CC and some writing style examples I get 90% there, sometimes 99%.
If you believe you don't have time for the last 1--10% you should not be in charge of writing any API used by anyone but yourself. Just my two c.
aDyslecticCrow
Ai is great at block comments, there is no excuse. Add to that a small anotated usage example written by a human and this whole post would have not existed.
Lack of docs also cripple AI from understanding, so future adoption becomes even more bleak.
If an api or library developer didnt bother doing even bare minimum docs, my confidence in the library drops aswell.
Did they skip testing aswell? Ran the happy path for a day and called it good?
This post sour my interest in zig. Its now obvious to me now why rust took much of its market.
foxes
I don't want to read ai slop comments. If you cant be bothered writing docs, I cant be bothered learning to use your library.
keyle
That would hurt adoption. I understand things move fast but if you want people to make the switch other than hello world, it has to be at a minimum cosy. Sending them to hell and find your way out isn't a good move long term.
I tried Zig a couple of times and I got that feeling: very powerful and clever language but not really for me, I don't have the headspace, sorry. I need something I can debug after an 8 hours dayjob, a commute and having put the kids to bed. It better be inviting & fun! (Hi, C).
null
hardwaresofton
Yeah, thinking about this attitude positively, maybe it’s a feature — if only hard core people can comfortably figure it out, you get higher quality contributions?
Not trying to imply that’s an explicit goal (probably instead just a resource problem), but an observation
ksec
I think it is a trade off for between zig's development speed and documentation. It is Pre 1.0, extreme beta mode with lots of breaking changes.
Generally speaking I think it is the right trade off for now. Purely inferring from Andrew and the Zig's team online character as I don't know them in person, I think they do care a lot of DX, things like compiling speed and tools. So I think once 1.0 come I won't be surprised if it will have extremely good documentation as well.
And I would argue, writing good, simple, clear, detailed documentation is actually harder than writing code itself.
chrisandchris
Contributions to the Zig language or contributions to software using Zig (the latter is the one the post is about as I understand)?
If so, I believe Zig will stay within a niche. Lower entry barriers allow "script kiddies" to easily start withe language, and they eventually will become leading engineers. Only a few people tend to go straight for the highest practice without "playing around". IMHO the reason, why PHP got so popular (it was not good back then, just very very easy to start with).
rjh29
I think it is intentional. They don't want to attract low-commitment beginners while the language is heavily changing (and explicitly in beta). Such people will ask questions and ask for documentation but contribute nothing.
littlestymaar
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.
(Loris Cro being a key community figure isn't helping in any way, and it's a good remainder that if you don't clear up your community from bullies from the beginning, they will turn your entire community to a miserable place. And that's a shame because from what I've seen, Andrew Kelley seems to be a very cool guy in addition to being very smart).
pjmlp
Not only, the whole handmade movement puts me off.
It is the anti-intelectualism from Go culture, gone wild against C++, Rust, Swift, anything modern, or even tools, using game engines versus doing the whole computer from scratch for a game.
kristoff_it
> 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.
Maybe, or maybe the fact that Zig is a small independent project with limited resources has also something to do with it, and this kind of shaming says less about Zig than you'd think.
When I first joined the Zig project, Zig was still using the bootstrap compiler written in C++ that would not free memory (it took more than 4GB to compile the Zig compiler). Some people at the time were asking us to prioritize work on the package manager but Andrew rightfully wanted to prioritize rewriting the compiler instead. In hindsight this was the obviously right decision: a package manager implies that one can very easily add an order of magnitude more code to their project, stressing the performance of the compiler. If we had not prioritized core infrastructure over giving people what they wanted faster, today we would have people complaining that adding a single dependency to their project makes the build impossible to complete.
The Zig project has a huge scope and we are a small independent organization. This makes us extremely nimble and efficient, but it does mean that we need to do things in the order that makes the most sense for the project, not for what the public wants.
The fact that we develop in the open doesn't mean that the language is ready yet.
People that already have the required domain knowledge (and who have a tolerance for breaking changes) will have the opportunity to be early adopters if they wish to do so, others will have to wait for Zig to become more mature. And we do make this clear in releases and all forms of public communication.
We have gone a long way since the bootstrap compiler days, but we are still missing key infrastructure:
- we have a x86_64 custom backend but aarch64 is not complete yet - incremental compilation is showing that we can get instant rebuilds of large projects, but it has missing features and it doesn't work on all platforms yet - we need native fuzzing since AFL keeps regressing everytime a new version of LLVM comes out - for the longest time we haven't had a strong I/O story, now we're finally working on it
The time for paving the road for a new generation of programmers will come (it's in the ZSF mission statement btw), but first we need to finish the plumbing.
jakobnissen
There is a cost to writing documentation - it takes time, which could be used to improve Zig in other areas. For code that is work-in-progress, it can make sense to not document until things are more settled.
Of course documentation is good. But if you have to prioritize either a new feature, or a critical bugfix, or documentation, you often can't have it all
simonask
I tend to actually disagree with this attitude, because I see writing documentation as really effective "rubber-ducking". If it's hard and time-consuming to properly document, it's probably hard to use, so extra effort should be spent to actually justify the design, not least to yourself in 6 months. If you can't justify it, it's probably wrong.
kelnos
This really struck a chord with me. Writing documentation is an act of explaining something to others. Explaining something to others is a great way to test your own understanding. If it's hard to explain to someone else, then maybe it's the wrong design.
If you don't through that exercise, you're much more likely to build confusing, difficult-to-use APIs.
pmarreck
100%.
Similar to how TDD forces you to first figure out the API of your code due to the test code being its first client.
hardwaresofton
This is a good point, but one could make a point for the usefulness of documentation in “thinking like a user” which is a valuable exercise.
I do very much prefer moving fast though, so I get it, docs-later is obviously a very valid way of doing things.
If someone is excited about Zig and wanted to make a difference I guess it’s now obvious where they could have outsized impact!
7bit
Docs later is an okay approach, when you build something in a closed environment, where the only users know the code inside out.
But when working in open-source and your goal is to have people adopt your software, then it's a bad point and a lazy excuse.
aDyslecticCrow
Then they should not have relead the new api at all. Why release half finnished library.
flohofwoe
Zig as a whole is half-finished, should it be kept under wraps until it is ready?
There's a reason for the 0.x version number, if you can't live with breaking changes, don't use Zig yet. It's as simple as that.
sureglymop
Because the language is not stable at this point and hasn't reached 1.0?
Are you saying one should never make anything half finished available to the public? This post proves why it is valuable to do so, they are getting valuable feedback and a discussion on hacker news for free.
7bit
Your argument implies that good documentation is not an improvement, which of course is wrong. It also belongs to the task of improving code. Why would you move away after half-assing the API, when you can add the docs and whole-ass it instead?
HeartofCPU
Very good point
wordofx
Na. It’s flat out laziness. Don’t make excuses. Either write docs or stop worrying code.
0x696C6961
Writing good docs/examples takes a lot of effort. It would be a waste considering the amount of churn that happens in zig at this point.
geon
Yes. For now, that effort is better spent writing clear test cases that can serve to illustrate the intended usage.
While tests aren’t quite as good documentation as actual documentation, they are guaranteed to not be out of date.
ulbu
i find that zig is too oriented at doling out directives for what not to do instead of just collecting and teaching variants of how and what to do. the lack of documentation on this interface is a sore case in point.
geon
You can’t expect documentation this early. The new interface was just released.
viraptor
In serious codebases docs are not an afterthought. There's lots of places where you're expected to add both a new interface and docs together.
7bit
[flagged]
wordofx
So zig isn’t a serious language. It’s just some trash apis thrown together.
pharrington
I'm not a Zig developer, but I imagine one reason why the Zig documentation is so spartan is because the language is still young and constantly evolving. It's really hard to devote the time and energy to writing documentation when you know that what you've written will just be wrong at some uncertain point in the future.
Galanwe
The Zig's language is really good, but the standard library is really a big work in progress, constantly shifting, missing a lot of bits, overly abstracted at some places and too low level at other places.
I would say just stay away from the standard library for now and use your OS API, unless you're willing to be a beta tester.
stop50
I have never understood libraries or imterfaces that want me to allocate buffers for their type. I can't parse them (no need for the lib then) or write to them (would probably break the exchange).
The weird interface of go is probably due the fact that some interfaces can be used to extemd the writer like the hijacker interface (ResponseWriter.(http.Hijacker)) and the request object is used multiple times with different middlewares interacting with it. In short: request does not need to be extended, but the response can be an websocket, an wrapped tcp connection or something else.
kelnos
> I have never understood libraries or imterfaces that want me to allocate buffers for their type.
That doesn't seem that odd to me. It's a trade off: more flexibility, but more manual work. Maybe I have a buffer that I've allocated that I'm not using anymore (say I have a buffer pool) and want to use it again. If the type allocates its own behind the scenes, I can't do that. Or maybe I'm working in an environment where I need to statically allocate all of my resources up-front, and can't allocate later.
The big downside is that if 90% of people are just going to allocate a buffer and pass it in, it sucks that 90% of people need to do more work and understand more minutiae when only 10% of the people actually need to. The holy grail is to give lots of flexibility, but make the simple/common case easy.
A simple improvement to this interface might be to allow the caller to pass a zero-length buffer (or Zig's version of null), and then the type will allocate its own buffer. Of course, there's still a documentation burden so people know they can do that. Another option could be to have second constructor function that takes no buffer arguments at all, which allocates the buffers and passes them to the fully-flexible constructor function.
geon
Isn’t the whole point of an external buffer that the function won’t need to allocate?
benreesman
It's just a different convention like radians and degrees.
You can lift/unlift in or out of arbitrary IO, in some languages one direction is called a mock, in other languages the opposite is called unsafeFoo.
Andrew Kelley independently rediscovered on a live stream 30 years of the best minds in Haskell writing papers.
So the future is Zig. He got there first.
pjmlp
Only if use after free story actually gets fixed, and not by repurposing what has already existed in the C and C++ ecosystems for the last 30 years, like PurifyPlus or VC++ debug allocator.
benreesman
If you mean running clang-tidy as a separate build step or ASAN in a different category than other soundness checks?
Compute is getting tight, lots of trends, the age of C++ is winding down gracefully. The age of Zig is emerging delibetately, and the stuff in the middle will end up in the same historical trash bin as everything else in the Altman Era: the misfortunes of losing sight of the technology.
null
danieltanfh95
its bad because they are mixing what was supposed to just be execution boundaries into the overall runtime engine without making it explicit how to bridge between one and another.
eps
Sounds mostly like a documentation issue, or the lack of thereof.
JaggerJo
Zig would be my go to language for low level stuff.
I think fact that Zig can be used as a C/C++ cross compiler is brilliant.
xmorse
If you are too dumb for it I don't have any hope
jedisct1
The new I/O interface makes printing a simple “Hello, world!” more complicated, but once you get used to it, the design is actually very clean, versatile, and future-proof.
Since 0.15, though, I feel too dumb for Zig’s ArrayList.
simonask
Is it future-proof though? Last I saw, it relied on some yet-to-be-determined design for compiling async variants of everything that uses IO, and it was still unclear whether it was possible at all to support dynamic dispatch.
My info could be outdated - I don't follow Zig very closely, but I am curious.
kristoff_it
The Reader/Writer changes are perfectly compatible with the upcoming async I/O stuff and you won't need to change any code that just deals with streams.
No promises about potential future changes though :^)
null
8s2ngy
I’m sorry, but any non-trivial Zig code gives me PTSD flashbacks of C. I don’t understand who Zig is targeting: with pervasive mutability, manual allocation, and a lack of proper sum types, it feels like a step back from languages such as Rust. If it is indeed a different way to write code, one that embraces default memory unsafety, why would I choose it over C, which has decades of work behind it?
Am I missing some context? I’d love to hear it.
sothatsit
I love Zig precisely because it is so similar to C. Honestly, if you don't like C, I can totally understand why you wouldn't like Zig. But I love C, and I love Zig.
Zig has become my go-to for projects where I would previously have reached for C, largely because Zig has such good compatibility with other C projects.
Rust, on the other hand, is a completely different beast. It is very different from C, and it is far more complicated. That makes it harder to justify using, whereas Zig is a very easy choice as an alternative to using C itself.
simonask
C is entirely as complicated as Rust, if your goal is to write correct software that doesn't crash all the time. It's only a syntactically simple language. Actually making anything interesting with it is _not_ simple.
ozgrakkurt
Compared to C:
Discriminated unions, error handling, comptime, defer.
Better default integer type casting, ability to choose between releaseSafe/releaseFast
And probably other things.
As for comparison to Rust, you do want very low level memory handling for writing databases as an example. It is extremely difficult to write low level libraries in Rust
simonask
I think the argument is that it is also extremely difficult to write low level libraries in Zig, just as it is in C. You will just only notice the difficulty at some later point after writing the code, potentially in production.
flohofwoe
> low level libraries in Zig, just as it is in C
Did you write any Zig code yet? In terms of enforced correctness in the language (e.g. no integer promotion, no implicit 'dangerous' casts, null-safety, enforced error handling, etc...) and runtime safety (range-, nullptr-, integer-overflow-checks etc...), Zig is much closer to Rust than it is to C and C++.
It "just" doesn't solve static memory safety and some (admittedly important) temporal memory safety issues (aka "use-after-free"), but it still makes it much harder to accidentially trigger memory corruption as a side effect in most situations that C and C++ let slip through via a mix of compile errors and runtime checks (and you get ASAN/UBSAN automatically enabled in debug builds, a debug allocator which detects memory leaks and use-after-free for heap-allocations (unfortunately not for stack allocations), and proper runtime stack traces - things that many C/C++ toolchains are still missing or don't enable by default).
There is still one notable issue: returning a reference to stack memory from a function - this is something that many unexperienced Zig programmers seem to stumble into, especially since Zig's slice syntax looks so 'innocent' (slices look too similar to arrays, but arrays are values, while slices are references - e.g. 'fat pointers') - and which IMHO needs some sort of solution (either a compile time error via watertight escape analysis, or at least some sort runtime check which panics when trying to access 'stale' data on the stack) - and maybe giving slices their own distinct syntax that doesn't overlap with arrays might also help a bit.
kristoff_it
> I think the argument is that it is also extremely difficult to write low level libraries in Zig, just as it is in C.
This has been not my experience at all in the ~6 years I've been writing Zig. I started having very little experience writing C (<1000, lines all written while in university) and since day 1 Zig has been a tremendous improvement over it, even back when it was at version 0.4.0.
flohofwoe
> a lack of proper sum types
Do you consider Rust enums 'proper sum types'? If yes what are Zig's tagged unions missing?
E.g.:
const Variant = union(enum) {
int: i32,
boolean: bool,
none,
fn truthy(self: Variant) bool {
return switch (self) {
Variant.int => |x_int| x_int != 0,
Variant.boolean => |x_bool| x_bool,
Variant.none => false,
};
}
};
kristoff_it
[flagged]
LAC-Tech
Zig is a systems programming language. I think that's probably who it's targeting.
People do systems programming in rust, but that's not really what most of the community is doing. And it's DEFINITELY not what the standard library is designed for.
konart
>People do systems programming in rust, but that's not really what most of the community is doing.
As someone who haven't done any systems programming after university: wait, what?
I was under impression that this is exactly what people where doing with Rust.(system apps, even linux kernel, no?)
If not - what do they (most if the community) are doing with Rust?
LAC-Tech
Web servers, games, and applications, that sort of thing.
Some people definitely do systems programming in, but it's a minority. The std library is not set up for it at all, you need something like rustix, but even that results in very unidiomatic ("unsafe") rust code.
In Zig it's all in the std library by default. Because it's a systems programming language, first and foremost.
simonask
Which part of the Rust standard library are you referring to here?
As far as I can tell, it contains many, many features that are irrelevant outside of systems programming scenarios with highly particular needs.
LAC-Tech
Let me answer your question with a question - how do you memory map in rust with the standard library?
In zig it's std.posix.mmap.
Author here.
I finally got it working. I had to flush both the encrypted writer and then the stream writer. There was also some issues with reading. Streaming works, but it'll always return 0 on the first read because Writer.Fixed doesn't implement sendFile, and thus after the first call, it internally switches from streaming mode to reading mode (1) and then things magically work.
Currently trying to get compression re-enabled in my websocket library.
(1) https://github.com/ziglang/zig/blob/47a2f2ddae9cc47ff6df7a71...