The article later says (about the server/client example)
> Unfortunately this code doesn’t express this requirement [of concurrency], which is why I called it a programming error
I gather that this is a quirk of the way async works in zig, because it would be correct in all the async runtimes I'm familiar with (e.g. python, js, golang).
My existing mental model is that "async" is just a syntactic tool to express concurrent programs. I think I'll have to learn more about how async works in zig.
I think a key distinction is that in many application-level languages, each thing you await exists autonomously and keeps doing things in the background whether you await it or not. In system-level languages like Rust (and presumably Zig) the things you await are generally passive, and only make forward progress if the caller awaits them.
This is an artifact of wanting to write async code in environments where "threads" and "malloc" aren't meaningful concepts.
Rust does have a notion of autonomous existence: tasks.