2017-05-19 16:03 GMT+02:00 Andrzej Krzemienski
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.
I can think of two ways of looking at the situation with a value-initialized error code: 1. Class outocme<T> has an invariant: putting it into state where it stores a value-initialized error code is a bug, close to undefined behavior, which means, you can assert() inside and users and algorithms can expect it never happens. 2. Class outcome<T> can be in yet another state: "strange". So we have the following states: valued, exceptional, errored, empty, and strange. And the user when inspecting the state has to take into account all the five possible states. I guess the same applies to a null exception_ptr. My preference would be #1, so that working with `outcome` is managable. Regards, &rzej;