@joepie91 like a general proper explanation for common consumption?
I think I have some understanding but wouldn't claim to be the expert. Can try a quick one.
@virtulis More a mental model / framing to reason about them, from the perspective of "implementing them in a compiler for a custom language", without ending up with a ton of duplicated complexity
@joepie91 Ah.
Well, I'll start in reverse.
A coroutine is any _code_ that executes independently of the main _call stack_ (but not necessarily in parallel, and usually not) and is started and controlled from that main call stack. Both async/await and generators can be considered coroutines, as well as CSP/Actors (not aware what the significant distinction between the two is).
The distinctinction between the types of them is then mostly about what triggers their execution and suspension/resumption.
Generators are directly started and resumed by the calling code (also passing in a value), but decide themselves when to pause or stop (also returning a value).
Async functions are started by the caller but then are controlled by the runtime itself, by being able to pass a promise to it and be resumed when the promise resolves. The caller uses the same mechanism to wait for the result/failure.
So I'd say the main difference is how the execution controlled and by what. Async functions are managed by an "executor", be it V8 or Tokio. Generators are managed by the caller. Processes in Erlang are managed by the VM but the message sending and listening are not coupled together.
I'm not aware of any implementations where the (synchronous) execution can be paused.
So I think in a language implementation all you need is a concept of a coroutine that can stop itself (with a value) and be resumed (with a value). The rest is "userspace".
Hope that was at least a bit useful :D
@virtulis It helped to solidify some of the details though, thanks :)