Zig's new plan for asynchronous programs
Async keywords and “function coloring”
- Several commenters dislike explicit
asynckeywords that “infect” call graphs; others find them useful as visible markers of potential I/O pauses. - Some argue that IO shouldn’t be uniquely marked; panics, allocation, stack usage etc. are equally “effects” and deserve a principled effect system rather than ad‑hoc
async. - There is debate over whether Zig’s approach actually removes coloring or just changes it from “async vs sync” to “does IO vs not”.
Zig’s Io model
- Zig introduces an explicit
Ioparameter for any function that may perform I/O; the same API works with:- blocking threaded runtimes (
Io.Threaded), - single-threaded variants,
- and planned evented / stackless coroutine runtimes.
- blocking threaded runtimes (
io.async(f, args)creates a future;future.await(io)waits;io.concurrentguarantees parallelism (or errors).- The same function is used for both sync and async I/O; the runtime choice lives in the
Ioinstance, not in function signatures or keywords.
Comparisons to other languages
- Rust:
asyncis seen as a half-effect-system bolted onto the type system (Future), causing ecosystem splits between sync and async APIs and runtime lock-in (e.g. Tokio). - Go: goroutines + channels seen as “green threads + queues”; some say Zig’s
Io.Queue+Io.selectcan replicate Go’sselect, others stress that Go channels’ rendezvous semantics and synchronization guarantees are heavier than simple futures or queues. - Haskell: many note the similarity to IO/Reader monads and explicit effect tokens, though Zig doesn’t treat them as monads in the language.
- JS, Python, C#: discussed as examples of “viral” async/await; Go and Java virtual threads as examples of colorless or “everything async” models.
Ergonomics, DI, and explicit effects
- Supporters like explicit
AllocatorandIoas “sweet smells” in a systems language: no hidden runtimes, easy to swap implementations, good for embedded and OS work. - Critics worry about “prop drilling” (passing
Io/Allocator through long call chains), and suggest context objects or DI frameworks; others strongly oppose such magic and prefer explicit parameters. - Some point out the ecosystem effect: if all std I/O uses
Io, libraries naturally become runtime-agnostic, unlike typical Rust/Python async splits.
Concurrency, safety, and structure
- Thread safety remains a concern: libraries must still reason about threaded vs single-threaded
Ioand document costs. - Structured concurrency patterns are possible via
Io.Groupanddefer future.cancel(io), but correctness still relies on programmer discipline. - Evented/stackless coroutine support and suspend/resume primitives are still under design; complex server and FFI scenarios are seen as important tests of the model.