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.
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
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)
* 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.
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.
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
( [](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
( [](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::vectorstd::function to hold the continuations. 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. I'll get my prototype working enough to submit to Microsoft first. If Gor is interested, he'll need to shepherd getting the MSVC optimiser to stop being so braindead when faced with this pattern. Gabi also told me at C++ Now to send this problem to him too as I was gently teasing him about how badly MSVC does here compared to everything else, and he said he'd do what he could to make them fix the optimiser. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/