Boost logo

Boost :

Subject: Re: [boost] [next gen future-promise] What to call the monadic return type?
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2015-05-25 12:37:55


On 25 May 2015 at 18:33, Avi Kivity wrote:

> > In particular, error_code is fast, and unexpected returns are not
> > exceptional and must be as fast as expected returns.
>
> As I mentioned, in this case the user can use expected<> or similar
> themselves.

As I mentioned, expected<> is too hard on compile times for large
code bases. It's also way overkill for what 98% of use cases need.

> Otherwise, what's the type of error_code? There could be an
> infinite amount of error_code types to choose from (starting with simple
> 'enum class'es and continuing with error codes that include more
> information about the error (nonscalar objects).

It's std::error_code. Same as ASIO uses. If being compiled as part of
Boost, I expect boost::error_code and boost::exception_ptr will work
too as additional variant options.

> > Also, any monadic transport would default construct to an unexpected
> > state of a null error_code in fact, which is constexpr. This lets one
> > work around a number of exception safety irritations where move
> > constructor of T is not noexcept more easily.
>
> I'm not sure how the default constructor of future<> and the move
> constructor of T are related.

Well, let's assume we're really talking about a maybe<T>, and
future<T> subclasses maybe<T> with additional thread safety stuff.

In this situation a maybe<T> doesn't need a default constructor, but
because it's a fixed variant we always know that error_code is
available, and error_code (a) doesn't allocate memory and (b) is STL
container friendly, so it seems sensible to make maybe<T> also STL
container friendly by letting it default to error_code.

The problem, as with the WG21 proposed variant, is getting move
assignment to not undefine behaviour the existing contents if the
throwing move constructor throws. Boost Variant's copy constructor
dynamically allocates a temporary copy of itself internally to give
that strong guarantee - this is unacceptable overhead for mine. So I
need some well defined state to default to if during move assignment
my move constructor throws after I have destructed my current state.
Defaulting to an error_code saying the move constructor threw is a
reasonable well defined outcome.

> I'm not even sure why future<> would require a default constructor.
> Seastar's doesn't have one.

My future promise is as close to a strict superset of the Concurrency
TS as is possible. It should be drop in replaceable in 99% of use
cases, with the only point of failure being if you are trying to use
allocators with your futures.

My future promise is also intended to enter the Boost.Thread rewrite
as the next gen future promise, if it proves popular.

> >>> ... turns into a "mov $5, %eax", so future<T> is now also a
> >>> lightweight monadic return transport capable of being directly
> >>> constructed.
>
> I'm looking forward to it! I've been bitten by the same compile time
> explosion problems and I'm curious to see how you solved them.

With a great deal of concentrated study of compiler diagnostics and
trial and error!

Once they are working and they are being unit tested per commit, I'll
get a CI failure every time I break it. That should make things
enormously easier going. Lots of machinery and scripting to come
before that though.

I've got everything working except the sequence:

promise<int> p;
p.set_value(5);
return p.get_future().get();

This should reduce to a mov $5, %eax, but currently does not for an
unknown reason. I'm just about to go experiment and see why.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ 
http://ie.linkedin.com/in/nialldouglas/



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