Boost logo

Boost :

Subject: Re: [boost] Boost.Outcome review - First questions
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-21 22:12:14


>> Outcome doesn't do SFINAE on its main constructors. It relies on simple
>> overloading which is much lower compile time cost.
> Maybe it has lower compile time, but it is not correct, isn't it?
> Would you suggest that std::expect shouldn't do SFINAE?

Outcome's Expected provides both a subset and a superset of your
Expected proposal.

I have promised to track closely your proposal paper, but I have no
interest in providing a perfect match to your proposal. Outcome lets you
seamlessly mix expected<T, E> with Outcomes and with *any arbitrary
third party error handling system* thanks to the policy based core
implementation. It therefore cannot exactly implement your proposal, it
needs to differ because it *is* different. My claim is that any code
written to use LEWG Expected will work exactly the same with Outcome's
Expected. If it does not, I will repair Outcome's Expected until code
using it works identically. I think this a very reasonable position to
take, especially as you are still changing the proposed Expected.

At the risk of slightly losing my temper, I need to say something I'll
probably regret later when people throw axes at me. But it's been
building for a few days now, and I need to vent.

Both you and Vinnie have called Outcome "over engineered". I
respectfully suggest neither of you understands the purpose of Outcome
the **framework** which is to provide a very low overhead universal
error handling framework. That's why there is the exact same CRTP policy
based basic_monad class being typedefed into the aliases expected<T, E>,
outcome<T>, result<T>, option<T>. They are all the same class and
object, just with policy-determined "personality" that lets them provide
differing semantics to each user, yet they all still operate seamlessly
together and can be fed into one another e.g. via the TRY operation, and
with very low, usually minimum, runtime overhead and low compile time
overhead.

If you are only in the market for just an expected<T, E> implementation
and nothing else, then yes Outcome looks over engineered. But my claim
is that in any real world code base of any size, people end up having to
add layers on top of expected<T, E> etc to aid interop between parts of
a large code base. They will have varying degrees of success, as people
on Reddit have told me regarding their local expected<T, E>
implementations. A lot of people end up with macros containing switch or
try catch statements to map between differing error handling systems.
And that is bad design.

I will claim that if you *are* building such an interop framework, you
will find that Outcome is the bare minimum implementation possible. It
is, if anything, *under* engineered compared to the many other
"universal error handling frameworks for C++" out there which tend to
throw memory allocation and smart pointers and type erasure at the problem.

Outcome doesn't do any of that, it never allocates memory, has highly
predictable latency, runs perfectly with C++ exceptions disabled, is an
excellent neighbour to all other C++ libraries AND build systems, and
avoids where possible imposing any constraints on the user supplied
types fed to it. It also lets you use as much or as little of itself as
you choose.

So okay, it's over engineered if you think you want just an expected<T,
E>. But as soon as you roll expected<T, E> out into your code, you are
going to find it won't be enough. Thus the rest of Outcome comes into
play, and even then there are small gaps in what Outcome provides which
any real world application will still need to fill. That's deliberate
*under* engineering, I couldn't decide on what was best for everyone, so
I give the end user the choice by providing many customisation points
and macro hooks.

I'll respond to your other comments in a separate reply. I just needed
to unload the above, and I appreciate that the docs do not sufficiently
get into the universal error handling framework part of Outcome. That is
due to repeated Reddit feedback telling me that earlier editions of the
docs didn't make sense, and I needed to go much slower and hold the
hand, so you got the current tutorial which as you've already observed,
is too long as it is. It would become even longer if you started
dissecting universal error handling strategies.

(And my thanks to Andrzej for the motivating example on the landing page
of the docs, he did a great job capturing the universal error handling
framework aspect of Outcome. I would love to know if reviewers can make
sense of it, or did it just confuse the hell out of everybody)

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