I’m working on an RFC for async/await syntax (as you may already know), and I definitely considered something in this space, where an async function and a generator are just the same thing (you may know this too, since I posted a gist on twitter a few months ago).
Ultimately I’ve moved away from that kind of unified design for a few reasons. First, I think users find it easier to model async and generators as separate functionalities when learning than to understand them as isomorphic. In contrast, I think the main benefit of unifying them is aesthetic, which isn’t supremely compelling.
The biggest reason not to do this, I think, is that I think having two separate functionalities makes it very easy to model streams, which currently are a bit of a problem syntactically (@Nemo157’s alternative pre-RFC has a proposal, but I’ll respond there why I’m unconvinced about that).
If we have both async fn()
and generator (let’s call that fn() yield
, we have a matrix:
Evaluated immediately | Evaluated asynchronously | |
---|---|---|
Return once | fn() -> T | async fn() -> T (Future) |
Yield many | fn() yield T (Iterator) | async fn() yield T (Stream) |