Live data from Hacker News

Zig's New Async I/O

kristoff.it

11–20 of 293 posts

Re: Zig's New Async I/O

#11

I'm generally a fan of Zig, but it's a little sad seeing them go all in on green threads (aka fibers, aka stackful coroutines). Rust got rid of their Runtime trait (the rough equivalent of Zig's Io) before 1.0 because it performed badly. Languages and OS's have had to learn this lesson the hard way over and over again: https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p13... > While fibers may have looked like…

I'm not sure how you got the perception that we're going "all in" on green threads, given that the article in OP explicitly mentions that we're hoping to have an implementation based on stackless coroutines, based on this Zig language proposal: https://github.com/ziglang/zig/issues/23446

Performance matters; we're not planning to forget that. If fibers turn out to have unacceptable performance characteristics, then they won't become a widely used implementation. Nothing discussed in this article precludes stackless coroutines from backing the "general purpose" `Io` implementation if that turns out to be the best approach.

Re: Zig's New Async I/O

#12
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

Aside from the ridiculous argument that function parameters color them, the assertion that you can’t call a function that takes IO from inside a function that does not is false, since you can initialize one to pass it in

Re: Zig's New Async I/O

#13

Earlier quoted context omitted.

It's hardly "all-in" if it is merely one choice of many, and the choice is made in the executable not in the library code.

I have definitely gotten the impression that green threads will be the favored implementation, from listening to core team members and hanging around the discord. Stackless coroutines don't even exist in the language currently.

In the 2026 roadmap talk Andrew Kelley spoke of the fact that stackless coroutines with iouring is the end goal here (but the requires an orthogonal improvement in the compiler for inlining that data to the stack where possible).

Re: Zig's New Async I/O

#14
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

Go also suffers from this form of “subtle coloring”.

If you’re working with goroutines, you would always pass in a context parameter to handle cancellation. Many library functions also require context, which poisons the rest of your functions.

Technically, you don’t have to use context for a goroutine and could stub every dependency with context.Background, but that’s very discouraged.

Re: Zig's New Async I/O

#15
Seeing a systems language like Zig require runtime polymorphism for something as common as standard IO operations seems off to me -- why force that runtime overhead on everyone when the concrete IO implementation could be known statically in almost all practical cases?

Re: Zig's New Async I/O

#16
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

Here's a trick to make every function red (or blue? I'm colorblind, you decide):

    var io: std.Io = undefined;

    pub fn main() !void {
       var impl = ...;
       io = impl.io();
    }
Just put io in a global variable and you won't have to worry about coloring in your application. Are your functions blue, red or green now?

Jokes aside, I agree that there's obviously a non-zero amount of friction to using the `Io` intreface, but it's something qualitatively very different from what causes actual real-world friction around the use of async await.

> but the general problem behind function coloring is that of context

I would disagree, to me the problem seems, from a practical perspective that:

1. Code can't be reused because the async keyword statically colors a function as red (e.g. python's blocking redis client and asyncio-redis). In Zig any function that wants to do Io, be it blue (non-async) or red (async) still has to take in that parameter so from that perspective the Io argument is irrelevant.

2. Using async and await opts you automatically into stackless coroutines with no way of preventing that. With this new I/O system even if you decide to use a library that interally uses async, you can still do blocking I/O, if you want.

To me these seems the real problems of function coloring.

Re: Zig's New Async I/O

#17

Earlier quoted context omitted.

I have definitely gotten the impression that green threads will be the favored implementation, from listening to core team members and hanging around the discord. Stackless coroutines don't even exist in the language currently.

In the 2026 roadmap talk Andrew Kelley spoke of the fact that stackless coroutines with iouring is the end goal here (but the requires an orthogonal improvement in the compiler for inlining that data to the stack where possible).

Do you have the timestamp? I watched that video when it came out and don't remember hearing it.

Re: Zig's New Async I/O

#18
post #15

Seeing a systems language like Zig require runtime polymorphism for something as common as standard IO operations seems off to me -- why force that runtime overhead on everyone when the concrete IO implementation could be known statically in almost all practical cases?

I think it's just the Zig philosophy to care more about binary size than speed. Allocators have the same tradeoff, ArrayListUnmanaged is not generic over the allocator, so every allocation uses dynamic dispatch. In practice the overhead of allocating or writing a file will dwarf the overhead of an indirect call. Can't argue with those binary sizes.

(And before anyone mentions it, devirtualization is a myth, sorry)

Re: Zig's New Async I/O

#19
post #12
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

Aside from the ridiculous argument that function parameters color them, the assertion that you can’t call a function that takes IO from inside a function that does not is false, since you can initialize one to pass it in

To me, there's no difference between the IO param and async/await. Adding either one causes it to not be callable from certain places.

As for the second thing:

You can do that, but... You can also do this in Rust. Yet nobody would say Rust has solved function coloring.

Also, check this part of the article:

> In the less common case when a program instantiates more than one Io implementation, virtual calls done through the Io interface will not be de-virtualized, ...

Doing that is an instant performance hit. Not to mention annoying to do.

Re: Zig's New Async I/O

#20
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

I think of it this way. Given an `io` you can, technically, build another one from it with the same interface. For example given an async IO runime, you could create an `io` object that is blocking (awaits every command eagerly). That's not too special - you can call sync functions from async functions. (But in JavaScript you'd have trouble calling a sync function that relies on `await`s inside, so that's still somet…

> but most modern apps rely on some form of dependency injection

Does Zig actually do anything here? If anything, this seems to be anti-Zig, where everything must be explicit.

Post reply on HN