Comment by gavinhoward
Comment by gavinhoward a day ago
As the author of a semi-famous post about how Zig has function colors [1], I decided to read up on this.
I see that blocking I/O is an option:
> The most basic implementation of `Io` is one that maps to blocking I/O operations.
So far, so good, but blocking I/O is not async.
There is a thread pool that uses blocking I/O. Still good so far, but blocking I/O is still not async.
Then there's green threads:
> This implementation uses `io_uring` on Linux and similar APIs on other OSs for performing I/O combined with a thread pool. The key difference is that in this implementation OS threads will juggle multiple async tasks in the form of green threads.
Okay, they went the Go route on this one. Still (sort of) not async, but there is an important limitation:
> This implementation requires having the ability to perform stack swapping on the target platform, meaning that it will not support WASM, for example.
But still no function colors, right?
Unfortunately not:
> This implementation [stackless coroutines] won’t be available immediately like the previous ones because it depends on reintroducing a special function calling convention and rewriting function bodies into state machines that don’t require an explicit stack to run.
(Emphasis added.)
And the function colors appear again.
Now, to be fair, since there are multiple implementation options, you can avoid function colors, especially since `Io` is a value. But those options are either:
* Use blocking I/O.
* Use threads with blocking I/O.
* Use green threads, which Rust removed [2] for good reasons [3]. It only works in Go because of the garbage collector.
In short, the real options are:
* Block (not async).
* Use green threads (with their problems).
* Function colors.
It doesn't appear that the function colors problem has been defeated. Also, it appears to me that the Zig team decided to have every concurrency technique in the hope that it would appear innovative.
[1]: https://gavinhoward.com/2022/04/i-believe-zig-has-function-c...
[2]: https://github.com/aturon/rfcs/blob/remove-runtime/active/00...
[3]: https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p13...
It’s hard to judge before stackless coroutines are reintroduced. But I think you’re entirely wrong that the next version of it will have colored functions, even according to your definition.
It has been mentioned that it’s possible that the default for debug builds is that every single function is compiled as an async function. I.e. there is canonically only one function color. Changing function color could become an optimisation for release builds. This is really not much different from inlining functions or other tricks the compiler can do with the calling convention if it has perfect knowledge of all callers.
> it appears to me that the Zig team decided to have every concurrency technique in the hope that it would appear innovative.
That’s a really bad take. It’s not much different from what they did to make allocators explicit. It’s an excellent approach for what Zig is supposed to be. Different concurrency models have different performance tradeoffs, just like with allocators. If the can support different IO models without making the language complicated, that’s a huge win, and they seem to be achieving that.
I find this approach the opposite of “appear innovative”. They’ve moved away from designing in a bunch of fancy syntax that locks users into one particular concurrency model, and gone for a more explicit and boring design which puts power in the hands of the user. It may not be right for everyone, but for what Zig is setting out to do it’s perfect. A disciplined decision in my opinion.
Getting stackless coroutines right for a low level language like Zig would be somewhat innovative. But not in a way that’s flashy or super interesting.