Date: Wed, 9 Aug 2023 11:28:30 -0400
On Wed, Aug 9, 2023 at 11:06 AM Stefan Sichler via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> Hi,
>
> I recently tried to add C++20 coroutine support to the I/O framework code of the company I'm working at and ran into very specific problems with the current implementation.
>
> There are also several oddities that literally instantly caught my eye, so I'd like to share my thoughts here:
>
>
>
>
>
> * Motivation
>
>
>
> - There is currently no way to implement a well-defined initialization of the promise_type from within the Coroutine's implementation body (and pass some parameters to the promise_type constructor).
You're not supposed to. The promise needs to exist *before* the
coroutine body. That means that meaningful initialization needs to
already have happened.
> - When looking through code, it is not directly obvious whether a function is a coroutine or not, because for deciding that, all of the function body has to be searched for a call to co_await, co_yield or co_return operators. This is very odd, because the compiler needs to add initialization code right at the very beginning of the function body anyway, if the function is a Coroutine.
While I can understand this to some degree, the compiler will notify
you really fast if you `return` from a coroutine or `co_await` in
something that already has a `return`. So it's unclear why a cursory
examination of a function needs to know if it is a coroutine or not.
Furthermore, the whole point of the coroutine system as designed is to
*not care* if a function is or is not a coroutine. All of that
machinery should be hidden, and the function body should look like
"normal code" as much as possible.
> - The return type of a Coroutine is forced to expose "promise_type" as part of the Coroutine signature, because it needs to be defined in its return type, but this should actually be an implementation detail of the Coroutine and thus should not be directly visible in the signature.
If you like, you can change how the coroutine's return type maps to
the promise type; the behavior you're citing is an overridable
default. However, I don't buy the notion that
`return_type::promise_type` being an accessible member of the return
type violates the notion of it being an implementation detail.
> - The promise_type cannot have a member field of type of the return type, because the promise_type needs to be declared inside the return type, so the type definition of the return type is incomplete at that point.
Why would the promise type need to have such a thing? If the two need
to intercommunicate, then they should do so via the return type having
a pointer/reference to the promise or a `coroutine_handle` or
something else. After all, the promise *creates* the return value
object; the promise has every opportunity to give it whatever it
needs.
> - The return object is created by promise_type::get_return_object() *before* the Coroutine implementation body had any chance of initializing the promise object by any means. (this was a major problem in my case that a had to work around in very ugly ways!)
Can you explain in detail why that was a problem? Try to post code
where you were doing this and having a problem. I'm getting the
impression that you were trying to implement coroutine machinery in a
way that clashes with its intended design.
<std-proposals_at_[hidden]> wrote:
>
> Hi,
>
> I recently tried to add C++20 coroutine support to the I/O framework code of the company I'm working at and ran into very specific problems with the current implementation.
>
> There are also several oddities that literally instantly caught my eye, so I'd like to share my thoughts here:
>
>
>
>
>
> * Motivation
>
>
>
> - There is currently no way to implement a well-defined initialization of the promise_type from within the Coroutine's implementation body (and pass some parameters to the promise_type constructor).
You're not supposed to. The promise needs to exist *before* the
coroutine body. That means that meaningful initialization needs to
already have happened.
> - When looking through code, it is not directly obvious whether a function is a coroutine or not, because for deciding that, all of the function body has to be searched for a call to co_await, co_yield or co_return operators. This is very odd, because the compiler needs to add initialization code right at the very beginning of the function body anyway, if the function is a Coroutine.
While I can understand this to some degree, the compiler will notify
you really fast if you `return` from a coroutine or `co_await` in
something that already has a `return`. So it's unclear why a cursory
examination of a function needs to know if it is a coroutine or not.
Furthermore, the whole point of the coroutine system as designed is to
*not care* if a function is or is not a coroutine. All of that
machinery should be hidden, and the function body should look like
"normal code" as much as possible.
> - The return type of a Coroutine is forced to expose "promise_type" as part of the Coroutine signature, because it needs to be defined in its return type, but this should actually be an implementation detail of the Coroutine and thus should not be directly visible in the signature.
If you like, you can change how the coroutine's return type maps to
the promise type; the behavior you're citing is an overridable
default. However, I don't buy the notion that
`return_type::promise_type` being an accessible member of the return
type violates the notion of it being an implementation detail.
> - The promise_type cannot have a member field of type of the return type, because the promise_type needs to be declared inside the return type, so the type definition of the return type is incomplete at that point.
Why would the promise type need to have such a thing? If the two need
to intercommunicate, then they should do so via the return type having
a pointer/reference to the promise or a `coroutine_handle` or
something else. After all, the promise *creates* the return value
object; the promise has every opportunity to give it whatever it
needs.
> - The return object is created by promise_type::get_return_object() *before* the Coroutine implementation body had any chance of initializing the promise object by any means. (this was a major problem in my case that a had to work around in very ugly ways!)
Can you explain in detail why that was a problem? Try to post code
where you were doing this and having a problem. I'm getting the
impression that you were trying to implement coroutine machinery in a
way that clashes with its intended design.
Received on 2023-08-09 15:28:43