In C++ coroutines, awaiters-types (i. e. argument-types of co_await and return types of initial_suspend/final_suspend) require the three methods await_ready(), await_suspend(std::coroutine_handle<...>) and await_resume(). I am aware of the order of invocation1 in case of suspension/resumption of a coroutine.
But it is unclear to me what is the rationale of demanding the distinct await_ready-method. When returning true invocation of await_suspend is prevented (and with it suspension altogether). However, the same effect is achievable by simply returning true from await_suspend.
In this blog article the author David Mazières says
await_readyis an optimization. If it returnstrue, thenco_awaitdoes not suspend the function. Of course, you could achieve the same effect inawait_suspend, by resuming (or not suspending) the current coroutine, but before callingawait_suspend, the compiler must bundle all state into the heap object referenced by the coroutine handle, which is potentially expensive.
However, to me this does not seem to be a valid argument: The (possibly heap-)allocated coroutine state needs to be created before promise_type::get_return_object() is invoked which is always invoked, since the promies_type-instance is part of the coroutine state. Therefore the coroutine state referenced by the handle is created anyway, regardless of whether we will invoke await_suspend or not.
Back to the question putting my thougths into code: I do not see in which case the rewriting of
struct awaiter
{
bool await_ready() { /* <arbitrary-await-ready-body> */ }
void /*| bool*/ await_suspend(std::coroutine_handle<...>) { /* <arbitrary-await-suspend-body> */ }
<any> await_resume() { ... }
};
to
struct awaiter
{
bool await_ready() { return false; } // always false
bool await_suspend(std::coroutine_handle<...>)
{
if (await_ready_result()) // effectively moved await_ready into await_suspend
return false;
/* <arbitrary-await-suspend-body> */
return true;
}
<any> await_resume() { ... }
private:
bool await_ready_result() { /* <arbitrary-await-ready-body> */ }; // could just be "in-lined" into await_suspend
};
would not be applicable. In the latter case awaiter_ready is obsolete without giving away any flexibility2. So what is the use of distinct awaiter_ready at all?
One thing that came to my mind was that await_ready could be kept noexcept when await_suspend's implementation is arbitrarily complex, which might allow for some optimization but that seems overly specific to be the actual rationale.
1: See for example the pseudo code block in section The Awaiter Workflow of article https://www.modernescpp.com/index.php/a-generic-data-stream-with-coroutines-in-c-20
2: I neglect the case of await_suspend returning some std::coroutine_handle, mainly because I don't see the particular use of that either. After all you could simply just call some_handle.resume() as last statement instead of returning it and instead return void/true. Feel free to enlighten me about that one as well.