C++ Logo

std-proposals

Advanced search

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

From: Stefan Sichler <stsichler_at_[hidden]>
Date: Fri, 11 Aug 2023 00:52:15 +0200
Am 10.08.23 um 16:16 schrieb Pavel Vazharov via Std-Proposals:
>
> Once all of the parameters have been copied into the coroutine frame,
> the coroutine then constructs the promise object. The reason the
> parameters are copied prior to the promise object being constructed is
> to allow the promise object to be given access to the post-copied
> parameters in its constructor.*First, the compiler checks to see if
> there is an overload of the promise constructor that can accept lvalue
> references to each of the copied parameters. If the compiler finds such
> an overload then the compiler generates a call to that constructor
> overload*. If it does not find such an overload then the compiler falls
> back to generating a call to the promise type’s default constructor.
>

Thank you, Pavel! I forgot about that detail. So the need for being able
to pass parameters to the promise constructor has already been identified!
For me, that only again emphasizes the need for some kind of explicit
initialization, like proposed in my initial post.

Let's image a promise type like this:

   promise_type
   {
     promise_type(void* some_arg_for_promise) { ... }
     ...
   };

And a coroutine like this:

   ret my_coroutine(t1 some_arg_for_coroutine, t2 some_arg_for_promise)
   {
     ...
   };

In that case, the c-tor parameters wouldn't match and the compiler would
yield an error.
So, I would be forced to also add the some_arg_for_coroutine parameter
to the promise c-tor, even though I actually don't need that value
there, just to be able to call that c-tor! Hm, that seems like a pretty
clumsy design.

So even here, an explicit initialization would bring relief! Then, I
could change the implementation of my coroutine to:

   ret my_coroutine(t1 some_arg_for_coroutine, t2 some_arg_for_promise)
     : co_init( promise_type { some_arg_for_promise } )
   {
     ...
   }


This is now clearly stating that only the some_arg_for_promise should be
passed on to the promise c-tor. This is ok, because the
some_arg_for_coroutine parameter is only consumed in the coroutine body
itself.
And not only that! It would also allow additional functionality, that is
currently completely inaccessible, like passing a "this" pointer or some
class member to the promise c-tor if the coroutine is itself a member
coroutine:

class my_class
{
   ret my_coroutine(t1 some_arg_for_coroutine, t2 some_arg_for_promise)
     : co_init( promise_type
         { this, some_arg_for_promise, _some_class_member } )
   {
     ...
   }
};


Last not least, one really big advantage that I again want to emphasize
here is that the promise_type can then completely be decoupled from the
coroutine signature, so the coroutine body, and *only* the coroutine
body now defines both the actual type of the promise and the parameters
to be passed to the c-tor of the promise.

Using this approach, there will be no more odd relationship between the
coroutine parameters and the promise c-tor and no more odd relationship
between the coroutine signature and its promise type.

Btw., as a goodie, this would also make coroutine_traits completely
superfluous without loosing any functionality!
And for those people still wanting to stick around with that, one could
write:

   ret my_coroutine(t1 some_arg_for_coroutine, t2 some_arg_for_promise)
     : co_init( coroutine_traits<ret, t1, t2>::promise_type
         { some_arg_for_coroutine, some_arg_for_promise } )
   {
     ...
   }

Received on 2023-08-10 22:52:19