This blog post imagines a programming language with “colored functions” – function are either blue or red, and differently-colored functions cannot be passed to or called from each other, plus have different calling conventions – as an analogy for async functions. The point, I suppose, is to show the unwieldiness of interactions between async and code. After trying to navigate [futures in Rust for a while](), I can see the point. As the author notes, futures don’t do much to solve the ugliness of the hand-off between sync and async code. There needs to ultimately be a method for handling separate independent callstacks.
One area where this manifests: API design. The API creator must decide whether to expose async functions, leaving sync users to de-async the result themselves, or sync functions, which async users are left to wrap (potentially wasteful, as the library had to do this itself at some point).
The HN comments for this post are insightful, with the top commenter noting that the red-blue language is “essentially Haskell” (with blue and red monoids), and another noting that golang solves this problem by making the whole program “red” (async).