Boost logo

Boost :

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


2017-05-19 16:03 GMT+02:00 Andrzej Krzemienski <akrzemi1_at_[hidden]>:

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

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;


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