Could you clarify (or provide more reading on) how the other systems like delimited continuations, algebraic effects, and monads differ from Zig async + how they could be adapted in a similarly unopinionated/low-level way?
The key requirement for all these is an ability/API to defer and resume execution (indeed, delimited continuations are sometimes described as "resumable exceptions"). In higher-level languages we'd just assume the presence of first-class functions/closures, and use those to describe these features. I'm less familiar with how that looks in a very low-level language like Zig, however these "async frames" appear (to my naïve eyes) to be analagous; hence why I'm interested whether one of those more-general primitives could be provided instead (the answer might be no!).
As for clarification on those features, here's a quick attempt. Firstly, note that all of these approaches are basically APIs to construct, consume, and combine (deferred) computations: they are unopinionated on how those computations get run (e.g. the user could supply a "main loop", or whatever).
Delimited continuations are like exceptions, except the stack (AKA continuation) is passed to the handler, which may choose to resume it. We can implement coroutines/async/yield/etc. by having handlers which put their continuation in a queue and pop off some other one to resume instead; we can get data parallelism by resuming a continuation many times; we can get backtracking by remembering old continuations and trying them again; we can get parsers, probabilistic programming, nondeterminism, etc. https://en.wikipedia.org/wiki/Delimited_continuation
Algebraic effects are similar, but defunctionalised: i.e. they represent control flow with datatypes, and are "interpreted" by a user-specified function.
I think you can implement delimited continuations in terms of async frames and memcpy (like in Lua you can implement call/cc in terms of the built-in coroutine library plus coroutine.clone). The language doesn't guarantee that this works though if you try to resume an async frame somewhere other than its original address.
Comments
The key requirement for all these is an ability/API to defer and resume execution (indeed, delimited continuations are sometimes described as "resumable exceptions"). In higher-level languages we'd just assume the presence of first-class functions/closures, and use those to describe these features. I'm less familiar with how that looks in a very low-level language like Zig, however these "async frames" appear (to my naïve eyes) to be analagous; hence why I'm interested whether one of those more-general primitives could be provided instead (the answer might be no!).
As for clarification on those features, here's a quick attempt. Firstly, note that all of these approaches are basically APIs to construct, consume, and combine (deferred) computations: they are unopinionated on how those computations get run (e.g. the user could supply a "main loop", or whatever).
Delimited continuations are like exceptions, except the stack (AKA continuation) is passed to the handler, which may choose to resume it. We can implement coroutines/async/yield/etc. by having handlers which put their continuation in a queue and pop off some other one to resume instead; we can get data parallelism by resuming a continuation many times; we can get backtracking by remembering old continuations and trying them again; we can get parsers, probabilistic programming, nondeterminism, etc. https://en.wikipedia.org/wiki/Delimited_continuation
Algebraic effects are similar, but defunctionalised: i.e. they represent control flow with datatypes, and are "interpreted" by a user-specified function.
Applicative is an API for combining two computations concurrently, e.g. the product of Foo and Bar is a single computation yielding a pair of results. Monad can likewise combine sequentially, where Bar depends on the result of Foo. These feel more abstract, but are equivalent to the above e.g. see https://okmij.org/ftp/continuations/implementations.html https://reasonablypolymorphic.com/#understanding-freer-monad...
I think you can implement delimited continuations in terms of async frames and memcpy (like in Lua you can implement call/cc in terms of the built-in coroutine library plus coroutine.clone). The language doesn't guarantee that this works though if you try to resume an async frame somewhere other than its original address.