Re: Capy Review

Andrzej Krzemienski via Boost <[email protected]> Fri, 26 Jun 2026 00:58:29 +0200
Newsgroups gmane.comp.lib.boost.devel
Message-ID <CAOenAXih_4TXqfuoMDpJdi5MqyA2VakV_yKWiV0xi98Y-SM1Xg@mail.gmail.com>
czw., 25 cze 2026 o 15:12 Vinnie Falco via Boost <[email protected]>
napisał(a):

> On Thu, Jun 25, 2026 at 4:56 AM Rainer Deyke via Boost <
> [email protected]> wrote:
>
> > Pretty sure that's not actually true.
>
>
> Capy provides an execution model for coroutines which offers one simple
> invariant:
>
>     A coroutine will always be resumed by the same Executor object which
> was used to launch it.
>
> This should probably be stated in the Capy docs up front.
>

Along with *why* this guarantee is important and worth trading other things
for.

Regards,
&rzej;


>
>
> > This isn't about Capy vs TooManyCooks.  This is Capy vs an entire world
> of
> > C++ coroutine code that can interact with each other more or less
> > seamlessly.
>
>
> Capy's invariant, stated plainly above, is the coroutine-native expression
> of the same invariant which Boost.Asio's execution model maintains. Asio's
> normative requirement, from
>
> https://www.boost.org/doc/libs/latest/doc/html/boost_asio/reference/asynchronous_operations.html
> :
>
>     The completion handler shall be submitted for execution as if by
> performing dispatch(ex2, std::move(f)).
>
> Asio got many things right. Capy takes those things and expresses them with
> a coroutine-native API. Or as I like to call it: coroutine-ONLY.
>
> Corosio similarly borrows the good parts of Asio unabashedly. And it uses
> Capy for its execution model. Both libraries, built from Boost.Asio's 24
> years of experience getting things right. There's a reason we asked Jeff
> Garland to be the review manager, as he was also the review manager for
> Boost.Asio.
>
> "Capy vs the entire world of C++ coroutine code" is actually "Capy
> continues 24 years of proven Boost design, while the rest of the coroutine
> world chose the path of least resistance."
>
>
> > And, to be clear, I'm reviewing Capy as a replacement for TMC, not as an
> > extension.
>
>
> Every misconception, misgiving, and misapprehension can be derived from a
> failure to understand the Capy execution model.
>
> One could infer that "you don't understand Capy" and I think that's both
> the charitable reading and also the correct reading. The documentation
> should make the invariant clear. That's on us. The documentation problem is
> surfacing in the Boost review, and this is a good thing. That's what Boost
> reviews are for. We've been steeping in it so long that we can't see it
> from the outside, for someone encountering it cold.
>
> Now let's review each of your objections through the lens of Capy's
> execution guarantees (some quotes are paraphrased):
>
> 1. "Capy wants to be the only coroutine library." This follows from not
> understanding why the boundary exists. The boundary enforces the invariant.
> It's the same reason Asio dispatches handlers through the associated
> executor instead of calling them directly. You called resume() manually.
> You called the handler directly. We don't do that.
>
> 2. "Capy is too restrictive to be useful." This conflates "I can't bypass
> the executor" with "I can't do anything." The restriction is the feature.
>
> 3. "Plain awaitables should just work." A plain awaitable can resume on any
> thread via raw coroutine_handle::resume(). That breaks the invariant. The
> compile error prevents it. You went around it.
>
> 4. "The two-call syntax is brittle." The two-phase syntax exists to deliver
> the frame allocator to operator new before the coroutine body executes.
> This is what supporting custom allocators looks like, which TMC doesn't
> offer.
>
> 5. "Not enough synchronization primitives." Your shared_mutex sketch calls
> coroutine_handle::resume() directly on the unlock thread. That breaks the
> invariant. An async_shared_mutex for Capy would need to dispatch through
> the executor. it is a reasonable feature request, but your proposed design
> is unsafe in Capy's model for the same reason it's unsafe in Asio's model.
>
> 6. "Not enough executors." You reviewed only Capy, not Corosio, which
> provides the concrete executors. This is the equivalent to reviewing Asio's
> executor model without looking at io_context.
>
> 7. "resume_on is better than run()." resume_on switches the current
> coroutine to a different executor without creating a new environment. run()
> creates a new io_env with the correct executor, stop token, and allocator.
> resume_on is simpler because it doesn't preserve the invariant across the
> transition. It trades away environment propagation for simpler syntax.
> That's a valid choice for TMC's model. It's not compatible with Capy's
> guarantees.
>
> 8. "The awaitable_wrapper can solve this generically." The wrapper calls
> resume() directly, doesn't dispatch through the executor, doesn't know
> which thread the foreign operation completes on. It breaks the invariant in
> exactly the way IoAwaitable prevents.
>
> 9. "TMC task runs without an executor." Manually calling
> resume()/done()/destroy() on a coroutine_handle. Works in a toy example,
> breaks invariants in production code.
>
> 10. "Capy is a trap." A trap implies hidden costs. The cost is explicit: a
> compile error when you try to bypass the executor. That's the opposite of a
> trap.
>
> Thanks
> _______________________________________________
> Boost mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> https://lists.boost.org/mailman3/lists/boost.lists.boost.org/
> Archived at:
> https://lists.boost.org/archives/list/[email protected]/message/QVN4UVUC4CK52RGNW5ORMWXXK7CKEGWY/
>
_______________________________________________
Boost mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://lists.boost.org/mailman3/lists/boost.lists.boost.org/
Archived at: https://lists.boost.org/archives/list/[email protected]/message/3OISEA7WWZ6WGITQP4OPAZFNZEZ6UCCP/