Boost logo

Boost :

Subject: Re: [boost] [next gen futures] Lightweight monad ready for inspection
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2015-06-21 04:00:21


Le 21/06/15 09:07, Vicente J. Botet Escriba a écrit :
> Le 19/06/15 19:03, Niall Douglas a écrit :
>> Some may remember the thread starting from
>> http://boost.2283326.n4.nabble.com/next-gen-future-promise-What-to-cal
>> l-the-monadic-return-type-td4676039.html and that I would firstly
>> prepare an optimally lightweight monad<T> for review here before
>> going on to base a next-gen lightweight future-promise on that
>> monad<T>.
>
> Nial, I don't understand why you call this class monad. I see it much
> more as a generalized optional_expected that allows the user to say
> which exception is thorw when there is an error type and not an
> exception type.
>
> IMO, the last parameter throw_error is really not needed.
>
> You can always wrap an error code with a class that states how to
> throw an exception. That means that we need an additional Error
> concept that defines the throw_error function, e.g.
>
> We could have a class that wraps an error with an exception
>
> template <class Error, class Exception>
> struct ThrowError {
> Error value;
> };
>
> template <class Error, class Exception>
> void throw_error(ThrowError<Error, Exception> const& e) {
> throw Exception(e.value);
> }
>
> Now the generalized optional/expected class will use the throw error
> whenever it needs to throw an exception and has an error type stored.
>
> BTW, why have you chosen a Callable for throw_error instead of
> directly the Exception?
>
>
> BTH, expected could already store an error or an exception_ptr. All
> you need is to have a class
>
> template <class Error, class Exception>
> struct ErrorOrException;
>
>
> Resuming you monad class is in some way an alias of
>
> expected<optional<R>, ErrorOrException<ThrowError<Error,
> ThrowException>, Exception>>
>
> possibly optimized with a specific specialization.
>
> BTW, why your class accepts only on Exception type and not a variadic
> set of Exceptions types?
>
>
> I have some trouble with the is_ready function. You say "True if monad
> is not empty.".
> Do you mean that oi will not be ready
>
> optional<int> oi;
>
> You need to add the preconditions of each function. No precondition
> mean the function is not partial.
>
> I don't see comparison operators, neither hash customization, was this
> intentional?
>
>
> I suspect that the exception thown by value() when an instance is
> empty is not future_error<no_state>,and that there is a type on the
> documentation. Or was this intentional?
>
> In the function value()&& you say
> "If contains a value_type, returns a rvalue reference to it, else
> throws an exception of future_error(no_state), system_error or the
> exception_type."
>
> Why system_error? Do you mean that when the exception_type given as
> parameter is exception_ptr, the exception throw is exception_ptr and
> not the stored exception? In the Expected proposal and in std::future,
> the exception throw will be the stored exception.
>
> The function has_exception is not coherent with the others state
> observer functions empty/has/value/has_error.
>
> What is the exact signature (or valid signatures) of the functions
> passed to map/bind/then?
> BTW, are these functions proposed?
>
> Last can the map function be applied to an empty instance? What would
> be the result?
>
I would like to suggest a different approach.

Given a class optionals<T1, ..., Tn>, which is a variant accepting to
be empty

we can see optionals<T, E1, ..., En> as an Error Monad, when all the Ei
are instances of the Error concept.

A class is a model of the Error concept if it defines the
rethrow_exception function.

When the optionals is empty the exception thrown is bad_optionals_access.

exception_ptr is a type erased Error that rethrows the stored exception.

std::error_code and std::error_condition can be seen as instances of the
type class Error if we define the rethrow_exception on them throwing an
system_error exception.

optionals<T1, ..., Tn> can not define all the function that your class
monad defines as they are too specific.

Instead of defining member functions we can define non-member functions.

has_value/has_error/value/set_value/set_error/get_error/emplace/map/bind/then

optionals<T1, ..., Tn> should be default constructible from Ti and
convertible to Ti using maybe a specific cast function.

optionals<T, E1, ..., En> must be implicitly convertible from the result
of throw_error(e).

We could also define a specific class as you propose with specific
semantic for the first argument that would defines member functions. I'm
not against this approach, nevertheless the main issue I have is how to
name this class :(

     result<T, E1, En> doesn't conveys the fact that it can be empty.
     monad<T, E1, En> is not good as Monad is a type class not a
concrete type.
     optional_result<T, E1, En> is too long
     optional_value_or_errors<T, E1, En> is too long

HTH,
Vicente


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