Boost logo

Boost :

Subject: Re: [boost] [outcome] High level summary of review feedback accepted so far
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2017-05-31 00:01:11


On 31/05/2017 11:47, Vicente J. Botet Escriba wrote:
> Le 31/05/2017 à 01:14, Gavin Lambert a écrit :
>> That's unavoidable for an empty state. It's like a NULL in a database
>> or the none_t state in an optional -- it's up to whoever uses it to
>> decide "the value is missing, and that's bad because it should have
>> had one" or "the value is missing but that's ok, it doesn't have to
>> have one".
> When I define functor::map/transform or monad::bind/chain, I need to
> know what is the value_type if the functor or the monad. If empty is
> part of the success alternatives it is part of the value_type. If
> success is part of the failure, it isn't part of the value_type.
> If we don't define if it is a success or a failure we are unable to
> define these functions.

Why do we care about monads?

>>>> But without that, it's still possible with:
>>>>
>>>> if (r.has_error()) { (void) r.value(); /* will throw */ }
>>> r.value(); // ;-)
>>
>> Your point being?
> It is the same. No need to check as value() do it already.

Well, ok. That's basically what I said in my followup post. It was a
contrived example constructed to be similar to the one that preceded it
(thereby explaining why it is not necessary to have exception() return
an exception in any but the actually-transporting-an-exception case).

> Why this is worse? We use the type system to prevent from user error.

Having no exception is not an error. Asking for the exception is also
not an error, because the exception can represent a state that means "I
don't have one".

This does require returning the exception_ptr by value. Is that what
you're really objecting to? Or are you just too wedded to the semantics
of variant? Like I said in the other thread, while I agree that the
internal storage can be formed from a variant, logically the behaviour
should not be that of a variant. Otherwise you'd just use a variant.

>> No, each one returns an error_code. They do exactly the same thing in
>> all cases. (Except perhaps expected, but that's because it's aiming
>> to follow a standard that might mandate different behaviour.)
> No, some returns the stored error code and others can calculate one that
> doesn't correspond to the error that was transported.
> Not all the functions that return an error_code must be named equal. A
> function must convey the intent.

They return an error_code that represents the state of the object. This
is either the actual transported error_code, or an error_code that means
"success", "an exception occurred", or "no value present". This does
not seem weird in any way to me.

Note that expected<T,E> can't do that, because it doesn't know how to
construct an E that represents anything; it can only return what was
transported or fail (either by UB or throw). Thus expected<T,E> is
forced to just be a plain variant with narrow interface. This makes it
a good building block but a bad end-user type. This is presumably what
motivated Niall to write result<T> and outcome<T> in the first place; I
believe he's even said so.


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