C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Coroutines: Add explicit initialization by "co_init" operator

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Fri, 11 Aug 2023 08:59:05 -0400
On Fri, Aug 11, 2023 at 5:28 AM Stefan Sichler <stsichler_at_[hidden]> wrote:
>
> @Jason:
>
> > I already outlined the fundamental misunderstanding prevalent in your coroutine design. We shouldn't add a feature for allowing people to couple things that don't need coupling.
>
> How can you know what needs coupling and what doesn't from the programmer's point of view?

Because that's how the system is designed. Each of these objects has a
purpose, and you're trying to change what those purposes are. And it's
not clear what is to be gained from that.

The job of the promise is to be the mechanism by which the eventual
result of a coroutine is handed to the user (it stores the return
value/exception). The job of the future is to be the user's interface
to that mechanism (it accesses the return value/exception stored by
the promise). The job of the type that the coroutine awaits on is to
resume the coroutine when that object completes its async execution
and pass its value along to it upon resumption.

By coupling the promise to whichever awaitable you happen to be using
in the coroutine, you *prevent* the coroutine from awaiting on
*anything* but the specific type(s) it expects. But there is no
purpose to this. The promise does not *need* to talk to the awaitable
type in order to shepherd values from the coroutine to the outside
word. By coupling them, you are creating a dependency that need not
exist.

> But anyway, my proposal somehow addresses the exact opposite: I try to point out that the current coroutine design does couple some things together for actual no reason and I try to show a possible solution on how to unravel that.

No, the promise and the future are two halves of the same concept.
You're trying to uncouple them so that you can couple one half of them
to something that it doesn't need to be coupled to.

>
>
> > C++ already covers this, as the first parameter for any member function in the lookup is always `*this`. Naturally C++23 continues with this with explicit object parameter functions.
>
> Currently, that does _not_ help with promise c-tors, see that code example:
>
> struct my_class
> {
> struct ret
> {
> struct promise_type
> {
> promise_type(my_class* p_class_instance, int value) { /* ... */ }
> /* .... */
> };
> };
>
> // ERROR: this will _not_ compile, because the "this" pointer is _not_ passed
> // on to the promise c-tor, thus the promise c-tor signature doesn't match
> // the coroutine signature.
> ret my_member_coroutine(int value)
> {
> /* ... */
> co_await /* .... */;
> }
> }
>
> (Note: the only way of passing the "this" pointer here to the coroutine is by wrapping it by another member function of the class that in turn calls the coroutine passing "this" as an additional parameter. For me, that looks like another ugly workaround showing a limitation of the current design.)
>
>
> > Can you give an example where this is useful, using a design that actually works the way coroutines are meant to work?
>
> I already tried to show a valid use case for coroutines that the initial designers obviously hadn't in mind. From your point of view, this is of course _not_ the way they are meant to work, because otherwise the initial design would already have covered that use case.

No, that's not my point of view. My point of view is that these types
all have a purpose and your design is using them against that purpose
*for no reason*.

There is nothing in your design that is *necessary*, that *must* be
coded the way you have coded it. You could redesign your system to
work with the coroutine system and it would be functionally equivalent
to what you have. In fact, it would be *better* since the promise
wouldn't be coupled with the awaitables anymore, and therefore a
coroutine could be written which co_awaits on multiple different kinds
of your external systems.

That's the point here: your system is extremely *limited* as you have
coded it. If you had coded it in accord with coroutine design, it
would not be so limited.

What you need to provide is a reason why your system *cannot* be
implemented in accord with coroutine design as well as a reason why
implementing it this way is essential and beneficial compared to the
alternatives. And no, treating the promise type as an "implementation
detail" isn't a good justification.

> But I think I will anyway try to meld down all your counter-arguments into a new revision of my proposal as soon as I find some time. You already helped me to see more clearly the actual point of my proposal.
>
> Greetings
> Stefan
>
>

Received on 2023-08-11 12:59:17