2017-05-19 15:42 GMT+02:00 Niall Douglas via Boost
Ok, I remember, both error_code and exception_ptr are default-constructible. It is not immediately clear to me that a default-constructed error_code represents a no-error condition.
A null error code is widely held to mean "no error". Ditto with exception_ptr. In any ASIO completion handler, you'll see:
void asio_handler(const error_code &ec, ...) { if(ec) handle_error(); ... }
In the blog post by Chris Kohlhoff you refer to, he uses the following enum for representing http error conditions:
``` enum class http_error { continue_request = 100, switching_protocols = 101, ok = 200, ... gateway_timeout = 504, version_not_supported = 505 }; ``` Which implies that numeric value 200 means no-error and a value initialized `http_error` is meaningless. Maybe this does not affect the value of a default-constructed `std::error_code`, but surely it adds to the confusion.
I have absolutely no idea why Chris chose "http_error" for that enum. It should have been "http_status" because those are the HTTP status codes as per https://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
I am also highly unsure why you'd choose the error_code infrastructure for these. It's not like almost all of the HTTP status codes (e.g. 306 Switch Proxy) can be any error condition except resource_temporarily_unavailable.
Vinnie, what does Beast do?
Therefore calling o.error() on a valued outcome returning a default constructed (null) error code is exactly correct: we return there is no error.
Only under some definition of "correct". By correct, you probably mean "not invoking UB" and "being compliant with your specification", but it is not intuitive at all that a function should return this or that when invoked in a context that is most likely a programmer's bug.
No, really a null error code meaning "no error here" is the widely held interpretation. The reason I cannot categorically says it means no error here is because the C++ standard guarantees that a null error code has value 0 and the **system** category. And that's a defect, I think they meant value 0 and the *generic* category, because if they had then the standard would categorically guarantee a null error code means no error here.
As it currently stands, the standard accidentally has made a null error code mean "system dependent behaviour" which if it didn't mean "no error here" would fundamentally wreck the Networking TS and the Filesystem TS. Yay.
No undefined behaviour needed, and you can write your code using Outcome with the hard assumption that o.error() will always return an accurate view of the current state. No need to check .has_error(), or anything like it.
Modulo this situation with `http_error::ok == 200`. But with this you are also saying, the library provides two ways for checking if you have an error:
o.has_error(); // option 1
This returns whether the outcome contains an error_code. Not whether there is an error.
Oh..
A program might return an outcome containing a null error_code. It probably is a bug,
Interesting. I need to think about it. But my first response would be. If a user cheats the system in this way, you should not try to rescue the situation.
but Outcome can't reasonably enforce how people misuse error_code, not least because of the C++ standard defect above.
o.error() == std::error_code{}; // option 2
Actually "!o.error()" but I think you meant to write that anyway.
This would be preferred over option 1. If the function returned an empty outcome, this would throw, but that is probably a good thing.
If I take your library, and also apply the "Sea of noexcept" approach, this means that if I call `if(o.error())` to check if I have an error, I might be triggering `std::terminate()`. Scary, but maybe this is ok, it you treat empty outcome as a really abnormal state.