Boost logo

Boost :

Subject: Re: [boost] [next gen future-promise] What to call the monadic return type?
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2015-05-26 13:56:26


Le 26/05/15 01:09, Niall Douglas a écrit :
> On 25 May 2015 at 23:35, Vicente J. Botet Escriba wrote:
>
>>> However, future<T> doesn't seem named very "monadic",
>> Why? Because we don't have mbind or the proposed next?
> No, merely the name "future<T>"!
>
> future<T> is fine for a thread safe monad. But for a faster, thread
> unsafe one, I was asking here purely for names.
>
> Names suggested so far are maybe, result, holder, value.

Neither result, holder nor value conveys the fact that the value can not
be there.
maybe<T> has already the connotation T or nothing as optional. There is
no place for error_code and exception_ptr.
If the type is not related to thread synchronization, here they are some
alternative names: probably_value<T>, probable<T>?
>
>>> so I am
>>> inclined to turn future<T> into a subclass of a type better named.
>> Sub-classing should be an implementation detail and I don't see how a
>> future could be a sub-class of a class that is not asynchronous itself.
> It's not a problem. My future<T> subclasses an internal
> implementation type monad<T, consuming> which does most of the work
> of a monad already. monad<> has no knowledge of synchronisation.
>
> I am simply proposing subclassing monad<T, consuming> with a thread
> unsafe subclass called <insert name here>. It has almost the same API
> as future as it shares a common code implementation.
I had the impression that you wanted to me future a subclass of <insert
name here>. I don't share this design.
>
>>> Options are:
>>>
>>> * result<T>
>> sync or async result?
> A result<T> has most of the future<T> API with the set APIs from
> promise<T>. So you might do:
>
> result<int> v(5);
> assert(v.get()==5);
> v.set_value(6);
> assert(v.get()==6);
> v.set_exception(foo());
> v.get(); // throws foo
> v.set_error(error_code);
> v.get(); // throws system_error(error_code)
This is quite close to expected, isn't it?
>
>>> * maybe<T>
>> we have already optional, isn't it?
> True. But I think a monadic transport supersets optional as it can
> have no value. So:
>
> result<int> v;
> assert(!v.is_ready());
> assert(!v.has_value());
> v.get(); // throws no_state.
>
> The compiler treats a default initialised monad identically to a void
> return i.e. zero overhead.
Ah, then the to be named type has the additional ready state. This is
closer to a valid future with the addition of the promise (setting)
interface.
>
>> Some comments, not always directly related to your
>> future/promise/expected design, but about the interaction between future
>> and expected.
>>
>> IMO, a future is not an expected (nor result or maybe). We can say that
>> a ready future behaves like an expected, but a future has an additional
>> state. Ready or not. The standard proposal and the future in
>> Boost.Thread has yet an additional state, valid or not.
>> So future has the following states invalid, not ready, valued or
>> exceptional.
>> We should be able to get an implementation that performs better if we
>> have less states. Would the future you want have all these states?
> My aim is to track, as closely as possible, the Concurrency TS.
> Including all its bad decisions which aren't too awful. So yes, I'd
> keep the standard states. I agree absolutely that makes my monad not
> expected, nor even a proper monad. I'd call it a "bastard C++ monad
> type" of the kind purists dislike.

I have no problem. There are not proper and dirty monads. Purist will
give you the good name. I see several nested monads.
IIUC, the type doesn't has the invalid state, isn't it?
>
>> A future can store itself the shared state when the state is not shared,
>> I suppose this is your idea and I think it is a good one.Let me know if
>> I'm wrong. Clearly this future doesn't need allocators, nor memory
>> allocation.
> Yes, either the promise or the future can keep the shared state. It
> always prefers to use the future where possible though.
>
>> We could have a conversion from an expected to a future. A future<T>
>> could be constructed from an expected<T>.
> Absolutely agreed.
>
>> I believe that we could have an future operation that extracts an
>> expected from a ready future or that it blocks until the future is
>> ready. In the same way we have future<T>::shared() that returns a
>> shared_future<T>, we could have a future<T>::expected() function that
>> returns an expected<T> (waiting if needed).
>>
>> If a continuation RetExpectedC returns an expected<C>, the decltype(f1)
>> could be future<C>
>>
>> auto f1 = f.then(RetExpectedC);
>>
>> We could also have a when_all/match that could be applied to any
>> probable valued type, including optional, expected, future, ...
>>
>> optional<int> a;
>> auto f4 = when_all(a, f).match<expected<int>>(
>> [](int i, int j ) { return 1; },
>> [](...) make_unexpected(MyException) ; }
>> );
>>
>> the type of f4 would be future<int>. The previous could be equivalent to
>>
>> auto f4 = when_all(f).then([a](future<int> b) {
>> return inspect(a, b.expected()).match<expected<int>>(
>> [](int a, int b )
>> { return a + b; },
>> [](nullopt_ i, auto const &j )
>> {
>> return ???;
>> }
>> );
>> });
>>
>>
>> auto f4 = when_all(a, f).next(
>> [](int i, int j ) { return 1; }
>> );
>>
>> but the result of when_all will be a future.
>>
>> The inspect(a, b, c) could be seen as a when_all applied to probably
>> valued instances that are all ready.
> expected integration is very far away for me. I'm even a fair
> distance from continuations, because getting a std::vector to
> constexpr collapse is tricky, and you need a
> std::vector<std::function> to hold the continuations.
Why do you need to store store a vector of continuations. You have just
one. What am I missing?

> My main goal is
> getting AFIO past peer review for now.
>
> However, I have been speaking with Gor @ Microsoft, and if I
> understand how his resumable functions implementation expands into
> boilerplate then non-allocating future-promise means he can simplify
> his implementation quite considerably, and improve its efficiency. No
> magic tricks for future shared state allocation needed anymore.
As others I'm waiting for a written proposal. But I think this is not on
your plans.

Vicente


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