Study Maps How Wildly Async/Await Semantics Differ Across Languages
Research paper formalizes nine async/await design dimensions, showing why seven language runtimes produce different results for the same program.
A new research paper shows that async/await, despite looking similar across languages like Python, Rust, and Swift, hides substantial semantic differences underneath. Running a simple 'fire-and-forget' background-task program across seven modern async runtimes produced four distinct outputs, and across three variations of the program, no two runtimes agreed on all outcomes.
To explain why, the authors identify nine async design dimensions that govern the observable behavior of async code, grouped by a task's lifecycle: Start of Life (Eagerness, Suspension), End of Life (Extent, Reference Strength, Destruction, Propagation), and Cancellation (Awareness, Direction, Persistence). For example, Swift and Python's Trio both choose 'Dynamic Extent'—tasks can't outlive their spawning function—but diverge on Destruction: Swift cancels orphaned tasks while Trio awaits them, producing different printed output for the same code shape.
The paper formalizes these dimensions into a small-step operational semantics for a core async calculus, letting the authors trace exactly which rule firings cause different runtimes to diverge. For engineers writing concurrent code across language boundaries, the work is a reminder that async/await syntax offers no guarantee of shared semantics.
This synthesis was produced from its source by AI; there is no human editor or manual review step. How we work