Boost logo

Boost :

Subject: Re: [boost] [outcome] Ternary logic -- need an example
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-05-19 14:03:06


2017-05-19 15:42 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:

> > 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.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk