On Wed, Jun 24, 2026 at 7:08 AM Rainer Deyke via Boost < boost@lists.boost.org> wrote:
Capy coroutines cannot co_await awaitables from other coroutine libraries.
What you are asking for is: capy::task f() { co_await foreign_task(); } Here's my question. A Capy coroutine runs in a particular execution context. TooManyCooks coroutines run in a TMC execution context. You want the Capy coroutine to co_await the TMC coroutine, but this doesn't make sense. The TMC coroutine has to be launched in a TMC execution context. The only way this could make sense is if both the Capy and the TMC tasks were running in the same context. Either the Capy execution context, or the TMC context. TMC tasks want to run in TMC contexts so this means the Capy task has to run in the TMC context. So now I have to ask, why use Capy at all? You aren't using Corosio, you aren't using byte-oriented streams, then why not just use TMC solely?
Capy coroutines cannot co_await awaitables at all unless these awaitables also model the IoAwaitable concept.
This is technically correct as described above and it misses the point entirely. If you are going to co_await a task launched on a foreign execution context then you need a launch function which returns an IoAwaitable. That would look like this: capy::task f() { co_await tmc_run( tmc_ex, foreign_task() ); } tmc_run is a custom launch function, tmc_ex is the foreign executor, and foreign_task() returns the foreign task. ...Capy wants to be the only coroutine library in your program
I want to highlight that not only is this incorrect, it is the opposite. Capy recognizes that programs may want multiple execution contexts each with their own task types optimized for their domain, and is specifically designed to be a good citizen in this environment. It scopes itself clearly (IoAwaitable), it generates a compile error when the scope would be exceeded (code trying to run tasks in a way that would break invariants), and it offers the tools to create the bridges (IoAwaitable, IoRunnable) to go from Capy's bounded scope elsewhere, and back, in a safe way that preserves invariants. The canonical example is the transition from reactor-based socket operations to GPU operations, and back. As described in the papers: *Consuming Senders from Coroutine-Native Code* https://isocpp.org/files/papers/P4092R1.pdf *Producing Senders from Coroutine-Native Code* https://isocpp.org/files/papers/P4093R1.pdf That is the entire point of the sender bridges. Thanks