Comment by unscaled
Let's revisit the original article[1]. It was not about arguments, but about the pain of writing callbacks and even async/await compared to writing the same code in Go. It had 5 well-defined claims about languages with colored functions:
1. Every function has a color.
This is true for the new zig approach: functions that deal with IO are red, functions that do not need to deal with IO are blue.
2. The way you call a function depends on its color.
This is also true for Zig: Red functions require an Io argument. Blue functions do not. Calling a red function means you need to have an Io argument.
3. You can only call a red function from within another red function.
You cannot call a function that requires an Io object in Zig without having an Io in context.
Yes, in theory you can use a global variable or initialize a new Io instance, but this is the same as the workarounds you can do for calling an async function from a non-async function For instance, in C# you can write 'Task.Run(() -> MyAsyncMethod()).Wait()'.
4. Red functions are more painful to call.
This is true in Zig again, since you have to pass down an Io instance.
You might say this is not a big nuisance and almost all functions require some argument or another... But by this measure, async/await is even less troublesome. Compare calling an async function in Javascript to an Io-colored function in Zig:
function foo() {
blueFunction(); // We don't add anything
}
async function bar() {
await redFunction(); // We just add "await"
}
And in Zig: fn foo() void {
blueFunction()
}
fn bar(io: Io) void {
redFunction(io); // We just add "io".
}
Zig is more troublesome since you don't just add a fixed keyword: you need a add a variable that is passed along through somewhere.5. Some core library functions are red.
This is also true in Zig: Some core library functions require an Io instance.
I'm not saying Zig has made the wrong choice here, but this is clearly not colorless I/O. And it's ok, since colorless I/O was always just hype.
---
[1] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
> This is also true for Zig: Red functions require an Io argument. Blue functions do not. Calling a red function means you need to have an Io argument.
I don't think that's necessarily true. Like with allocators, it should be possible to pass the IO pointer into a library's init function once, and then use that pointer in any library function that needs to do IO. The Zig stdlib doesn't use that approach anymore for allocators, but not because of technical restrictions but for 'transparency' (it's immediately obvious which function allocates under the hood and which doesn't).
Now the question is, does an IO parameter in a library's init function color the entire library, or only the init function? ;P
PS: you could even store the IO pointer in a public global making it visible to all code that needs to do IO, which makes the coloring question even murkier. It will be interesting though how the not-yet-implemented stackless coroutine (e.g. 'code-transform-async') IO system will deal with such situations.