
What Is Zig's “Colorblind” Async/Await? - kristoff_it
https://kristoff.it/blog/zig-colorblind-async-await/
======
atombender
Zig's use of "async" as a _call-site_ modifier is exactly how I've long wished
async/await had been done in languages like JavaScript and Rust. It completely
fixes the "color" problem.

I brought it up on HN once, and apparently this was discussed as an option for
Rust, but for whatever reason, people didn't like it. To be fair, Rust has
certain design requirements that might not be compatible with such a system.

~~~
j-pb
The reason is that it creates completely unexpected bugs, like deadlocks.

Static function coloring based in asyncronicity is a feature not a bug.

Making it "dynamic" is like saying: "Yeah we've decided that if you just treat
an Option as a value, we will let you do it, and we'll also treat every Option
boxing inside your map as a noop."

------
howeyc
when set to .blocking

> The function is no longer async, and in fact both keywords basically become
> no-ops

That sounds crazy to me, if I use a keyword I expect it to behave the same
everywhere I use it. I hope I misunderstood, and that setting come kind of
global const can't "disable" async for one library, but still have it enabled
when used somewhere else. I would have to keep track of all these various
consts to know my app is/isn't actually doing async tasks, even though I've
explicitly used the keyword.

~~~
kristoff_it
It's not a switch for libraries, it's a global project-wide switch. It enables
or disables evented I/O for your whole application. Libraries can read that
setting and specialize at compile-time appropriately.

~~~
Matthias247
What I find a little bit surprising with this is that the behavior of a
library can be changed outside of its view. E.g. if the library requires to
always run in an evented mode (because it needs to spawn many small tasks),
then the application developer settings things into threaded mode might
prevent the library from working properly.

Similar questions might arise around cancellation and timeouts, which are
different to perform in an async/evented environment than a synchronous one.

In most other worlds the problem is "solved" by declaring a subsystem of the
application as async. And only that subsystem is running one or more
eventloops. That obviously introduces a different set of issues, but it
isolates parts of a program against others.

I'm really curious on how Zigs approach will work out in any bigger
applications where libraries from various parties would get used.

~~~
kristoff_it
> What I find a little bit surprising with this is that the behavior of a
> library can be changed outside of its view. E.g. if the library requires to
> always run in an evented mode (because it needs to spawn many small tasks),
> then the application developer settings things into threaded mode might
> prevent the library from working properly.

In that case you would add in such library a line like this:

    
    
      if (!std.io.is_async) @compileError("LIB doesn't support blocking mode");
    

> I'm really curious on how Zigs approach will work out in any bigger
> applications where libraries from various parties would get used.

That's an open question. In general Zig is more like C than C++ also when it
comes to expectations from libraries. We'll see where this will get us.

~~~
Matthias247
> In that case you would add in such library a line like this:

That's certainly an approach to make sure libraries run in the correct
environment. But it still doesn't seem to enable use-cases where you run an
eventloop on some threads and blocking IO (or just blocking on the eventloop)
on other threads, which are often found in bigger programs that are made up of
a lot of heterogenous libraries.

One could say "you might not need that - just run everything async". But since
we are talking about a system programming language where libraries might be
exported and used in different projects I'm not sure if that lack of
flexbility won't hurt long term.

~~~
kristoff_it
I think I understand what you're saying. In this introduction I just wanted to
give a feeling to people about the biggest building blocks so I didn't have
the opportunity of diving into the small details (the article is already
fairly long as is).

Zig doesn't take shortcuts when it comes to give people control over the
machine so what you describe is expected to be possible. The async part of the
language is still being worked on (Zig is at v0.6.0 as I write) and the top
level API will be reworked if it turns out to be problematic (that's the
superpower of being at a version < 1.0).

------
skybrian
It seems like this should work so long as popular libraries support both
modes. That should be easier to do in Zig, but if there is a popular library
that can only support one mode or the other, or worse, two popular libraries
that only support opposite modes, it will constrain any downstream
dependencies as well, and you have colored functions again.

But will you get an error at compile time, or will the system just deadlock?

This might be something that just needs to be handled socially, by convention,
much like you're not supposed to use too much unsafe code in Rust, and you
should make sure that public API's are safe.

------
fooyc
This looks like Go: The code is synchronous, but I/O uses polling under the
hood, so that the programmer gets the best of both worlds.

When a Goroutine would block, it's parked by the scheduler, thus allowing an
other Goroutine to execute. And it's not only about I/O: This works for any
syscall, or even for CPU-bound computations.

There is no clever trick from the compiler to allow this: There is just a hook
to the scheduler in low-level I/O code as well as before and after syscalls.

------
gfs
Is there any difference in the `.evented` example and the example that
explicitly uses the `async` and `await` keywords?

~~~
tingletech
the async await example is python, the rest of the code is zig

~~~
gfs
Sorry, I meant this one: [https://kristoff.it/blog/zig-colorblind-async-
await/#express...](https://kristoff.it/blog/zig-colorblind-async-
await/#expressing-concurrency)

~~~
kristoff_it
The two examples are perfectly equivalent.

