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. A program might return an outcome containing a null error_code. It probably is a bug, 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.
And by describing clear semantics for option 2, you are saying, it is equally fine to use option 2 for checking if we have an error. This encourages the usage of option 2, but I would not want my colleague programmers to start using this syntax, because I then cannot tell proper usages from inadvertent omissions. And reading the value of `error()` without having confirmed that some error occurred is almost surely a bug, even if you can assign a well defined semantics in `boost::outcome` for it.
Option 1 is misleading. Option 2 is correct, and means typing less boilerplate e.g. if(o.error()) ... instead of if(o.has_error() && o.error()) ...
I am fine with this scope disabled. However, `tribool` is still in scope, so I consider it valid to ask about its usefulness (especially given that all contexts in which it would prove useful is disabled). Maybe `tribool` should be also removed from the scope?
I believe you've convinced me to move tribool to under the advanced operations macro. Thanks. Logged to https://github.com/ned14/boost.outcome/issues/22 Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/