Boost logo

Boost :

Subject: Re: [boost] Boost.Outcome review - First questions
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2017-05-25 14:26:40


Le 25/05/2017 à 14:41, Hartmut Kaiser a écrit :
> Thanks Vicente,
>
>>>> There is still this case where you want to avoid exceptions in one part
>> of
>>>> the program, but still use exceptions in other parts of the program.
>> For
>>>> one example. in one "task" you launch another task with a callback
>>>> function `f`. You might want to throw from `f` and this is valid. But
>> the
>>>> framework for launching tasks cannot afford to spill exceptions, so
>> they
>>>> have to catch and somehow transport the exception (e.g., by
>> exception_ptr)
>>>> then in the other task, you might want to re-convert to an exception.
>>>> (something similar to what std::future does.)
>>> I understand what you're saying, std::future needs a (conceptual)
>> variant<T, exception_ptr> to store its state. So if I hear you correctly,
>> outcome::expected<T, exception_ptr> could be used for that.
>> I believe that yes, the underlying type of a future is an
>> expected<T,exception_ptr>.
>> Once the future is ready it has an expected in. I believe that we could
>> even have it at the interface level. For me the future::then function
>> should have a expected<T,exception_ptr> parameter, as this is the value
>> you can find when the callback is called.
>> But one thing at a time. First we need expected in the standard.
> Nod, I tend to agree with this. Even if calling the continuation with a
> variant<T, E> would give us the same semantics, especially with the monadic
> helper functions you mention below.
Glad to hear you like them.
>
>>>> Also, maybe you will find of use the following example that tries to
>>>> illustrate the basic use case of the library:
>>> <snipped code example>
>>>
>>> Thanks, I think I've seen this in the docs. All of this could have been
>> done with a variant<T, some_error_type> without changing the semantics,
>> yes?
>> With the code it will be easier to answer :) Sorry, I was unable to find
>> it.
>>
>> If we had some PossibleValued, MonadError interfaces, variant<T, error>
>> could be enough. As most of us we know Either T E is a Monad Error once
>> we do the mapping. But we don't have them yet (at least not in the
>> standard.
> Yes, I'd rather have those monadic functions which could generically work
> with any conceptually matching type than a special expected<> which mostly
> duplicates functionality provided by another (already existing!) fundamental
> type (variant<>)
Yes, but std::variant doesn't ensure the never-empty warranties. As I
said in another post I would like to have some std::variant that ensures
that. Anyway, I fill that is is clear to return a expected<T,E> than a
variant<T,E>, and not al the people is used to use the monadic
interface. A lot of people fill more comfortable with the interface of a
Possibly Value type where we have accessors.
>
>>> So I guess the next question I would like to ask is: what is the benefit
>> of using outcome::result<T> over std::optional<T>, and
>> outcome::expected<T, E> over std::variant<T, E>?
>> Can I try to answer what are the benefits of using std::optional<T>
>> instead of variant<nullopt_t,T>?
>> The same answer should apply to your last question, isn't it?
> Even if variant<nullopt_t, T> may be semantically somewhat equivalent to an
> optional<T>, the mere fact that you have to deal with nullopt_t makes the
> former awkward to use. In the case of variant<T, E>/expected<T, E> no
> additional awkwardness arises (AFAICS), especially if we had those generic
> monadic functions.
In order to be fair, we will need variant<T, unexpected_type<E>>.

And if we wanted the constructor from T to be explicit (thing that we
don't have yet) we will need variant<expected_type<T>,
unexpected_type<E>>. Note that in Haskell every type has a type
constructor and

Either T U = Left E | Right U

expected_type and unexpected_type play the roles of Left and Right for
expected.

>
> The only effect from introducing expected<> over variant<> + monadic
> functions would be a nice bulk of near duplication of code. If we had those
> (functions), then a simple using expected<T, E> = variant<T, E>; would do
> the trick to even get the same syntax.
>
If we had a variant with the never-empty warranties, the implementation
of expected will be not only simple, but also very short.
Hopping the expected proposal will push to have a strong std::variant
for C++20.

Best,
Vicente


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