Boost logo

Boost :

Subject: Re: [boost] expected/result/etc
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2016-02-05 04:25:09


On 4 Feb 2016 at 23:02, Domagoj Saric wrote:

> > You could theoretically pass exceptions function-to-function by
> > exception_ptr but that seems backwards, no pun intended. :)
>
> And we could theoretically and practically ;) return actual error
> objects (even those considered 'exceptions', e.g. std::runtime_error)
> w/o necessarily stuffing them into some type erasing mechanism like
> exception_ptr (i.e. you pass the ball as a ball until you need to
> interact with someone who only understands abstract UFOs;)

exception_ptr is like shared_ptr - the potential use of atomics
forces the compiler to emit code just in case. Any potential use of
atomics is like calling fsync() on the compiler's AST.

> https://github.com/psiha/err/blob/master/include/boost/err/errno.hpp
> https://github.com/psiha/err/blob/master/include/boost/err/win32.hpp

Firstly I just found and read your RFC on this potential Boost.Err at
http://lists.boost.org/Archives/boost/2015/11/226558.php. You posted
this during my vacation away from Boost, so I didn't see it till now.
I'd like to thank you for this contribution to the debate, it
certainly is original.

There are some very interesting - perhaps even debatable - feature
choices in this object. I'll skip commenting on most of those, but I
will say one thing - I've found in AFIO v2 the ability to use
outcome::result<T> as a receiving container surprisingly useful. The
pattern looks like this:

1. User hands some scatter buffers to be filled by a
file_handle::async_read() to AFIO v2. These probably are a
std::vector<std::pair<char *, size_t>>.

2. AFIO dynamically allocates a file_handle::io_state to represent
the i/o (memory allocation is unavoidable, but in AFIO v2 there is
exactly one memory allocation and deallocation per i/o now, unlike
eight allocations and deallocations in v1) and move constructs the
user's scatter buffers into an
outcome::result<std::vector<std::pair<char *, size_t>>> living inside
the file_handle::io_state.

3. For each completing buffer in the scatter list, if there was an
error we set the outcome::result<> to that error. If not errored and
the outcome::result<> does not hold an error, we update the buffer
with the transfer achieved.

4. Once all buffers are completed, we invoke whatever completion
handler of type U&& the user specified, passing through the
file_handle::io_state.

In other words, I found my result<T> very useful as a state
accumulator which can "go errored" in a natural way. Some may note
that we throw away all errors but the first received one, but that's
fine in this use case - I cannot think of a use case where an end
user cares if parts of a scatter-gather operation succeed and others
fail, if they did they'd split up the scatter-gather list into
separate operations.

Your Err object can't do value semantics - it cannot be a container
in its own right. I personally think that is unfortunate for the
reasons above. I think there is much more usefulness in these objects
having full value semantics BUT with a restricted variant content, so
basically either it's the value you want OR it's why there isn't a
value you expect there.

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