task<> coro(any_stream& s)
{
auto [ec, n] = co_await s.read_some(buf); // may throw
// ...
}
Calling and co_awaiting on a stream operation may:
- either throw, for instance upon allocator failure (not necessarily OOM: wg21.link/P1404),
- or return a non-zero
error_code, for instance upon expected EOF.
The exception path is clear: the programmer is not expecting this: their code is not prepared, so it has to be skipped: stack unwinding.
The non-zero error_code is tricky. Does it represent an error? What does _error_even mean?
The only practical or relevant meaning is "what does the function guarantee?"or in other words "what is the postcondition?" Whatever is guaranteed, the caller may take it for granted and is relieved of thinking about what happens if the guarantee is not fulfilled.
So, the question for co_await s.read_some(buf) is: do you guarantee that the buffer will be filled, or do I need to be prepared for the situation where it is not? The answer is probably "no guarantee, be prepared!" But if so, then:
- The library should document it clearly.
- It should consistently stick to this view: a non-zero
error_code is a success, irregular but success, that is, no precondition failure. In that case when_all/when_any should also recognize a non-zero error_code as success: the caller of the algorithm will determine what to do with the irregular successes.
When doing (for whatever reason):
co_await when_any(
stream1.read_some(buf1),
stream2.read_some(buf2),
);
You should get the first that returns even with a non-zero ec; even if the other one would have returned with a zero ec. Because this is the contract of stream1.read_some(buf1): getting a non-zero ec is success.
Calling and
co_awaiting on a stream operation may:error_code, for instance upon expected EOF.The exception path is clear: the programmer is not expecting this: their code is not prepared, so it has to be skipped: stack unwinding.
The non-zero
error_codeis tricky. Does it represent an error? What does _error_even mean?The only practical or relevant meaning is "what does the function guarantee?"or in other words "what is the postcondition?" Whatever is guaranteed, the caller may take it for granted and is relieved of thinking about what happens if the guarantee is not fulfilled.
So, the question for
co_await s.read_some(buf)is: do you guarantee that the buffer will be filled, or do I need to be prepared for the situation where it is not? The answer is probably "no guarantee, be prepared!" But if so, then:error_codeis a success, irregular but success, that is, no precondition failure. In that casewhen_all/when_anyshould also recognize a non-zeroerror_codeas success: the caller of the algorithm will determine what to do with the irregular successes.When doing (for whatever reason):
You should get the first that returns even with a non-zero
ec; even if the other one would have returned with a zeroec. Because this is the contract ofstream1.read_some(buf1): getting a non-zeroecis success.