Boost logo

Boost :

Subject: Re: [boost] [outcome] Second high level summary of review feedback accepted so far
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-31 11:26:06


On 30/05/2017 22:18, Peter Dimov via Boost wrote:
> Getting people a library that has a multitude of result classes would
> obviously be better than nothing, but how would it move us toward the
> goal of having std::result?
>
> How Boost originally worked was, when there is disagreement as to how
> some component should work, we hammer out our differences here, produce
> a consensus design, produce, as a result of our process, a rationale of
> why we arrived at this consensus and how, get the library into the hands
> of our users, listen to their feedback, refine as necessary, then hand
> the finished product to the LWG.
>
> When some people want X, others Y, a third group Z, it's always the path
> of least resistance to just put X+Y+Z into the library, or a
> policy-based factory that can create 6^11 classes, among them X, Y, and
> Z. But that's really a cop-out.

You may remember back at the very beginning of this review I said that
these objects were different to normal C++ design principles, there was
a multitude of ways of using them and hence so many varieties of usage
style in their API. I said that for most of my libraries, I decide on
one single clean design and use model, but for this library I really did
feel that multi-modal usage was more appropriate.

Thanks to this review we have reduced down that multi-modal API into
simplified categories, and hived those out into separate types so the
type tells the user the semantic, all with a substantial reduction in
member function count. All a definite improvement in my opinion.

I don't agree that this is a cop-out. I believe that empty vs non-empty
is a very obvious design improvement, it significantly improves the
clarity of contract of public APIs using these objects by indicating
whether an empty state can ever be returned.

The wide vs narrow is much less obvious. During these last few days to
put code to the problem, I put together a toy Outcome implementation
using nothing but templates and std::variant<> (my very first ever C++
17 program yay!) using:

// Statically checked T|error_code
template <class T>
using static_checked_result =
    outcome<T, std::error_code, void, default_to::disabled,
            emptiness::never, observers::narrow>;

// Runtime checked T|error_code
template <class T>
using runtime_checked_result =
    outcome<T, std::error_code, void, default_to::empty,
            emptiness::formal, observers::wide>;

... and tried using them in various use cases. I can find absolutely no
difference in runtime overhead. So that makes the sole difference to be
whether you prefer the compiler to tell you about the obvious null
pointer dereference in *std::get_if(&variant) if it's clever enough, or
whether you prefer some runtime default action to occur instead of
dereferencing a null pointer which is an instant segfault.

The former traps logic errors missed by the compiler at runtime
effectively. The latter lets the programmer skip typing out boilerplate.

But flipping the perspective, the former means your program may die
unexpectedly in production due to some untested branch combination. The
latter hides logic errors and therefore programmer bugs.

I know you think this a cop out, but I think those two are unresolvable.
Outcome may simply choose to implement one set and not the other out of
ideological purity, but I think that a "cut off one's nose to spite
one's face" type of decision.

It's a different form of cop out: we can't resolve this, so we choose
one and screw the other.

> (*) Not quite because the straightforward implementation would throw
> system_error instead of filesystem_error on value() and we'll lose the
> path, which is an interesting angle that we need to explore.

What we really actually need is an error_code which can carry payload.
Lawrence's status_code is heading the right way, but I am not keen on
his formulation. I have a gut feeling that we can do better, though
avoiding malloc and keeping the object useful is hard.

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