Boost logo

Boost :

Subject: Re: [boost] Boost.Outcome review - First questions
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2017-05-22 22:10:16


Le 22/05/2017 à 00:12, Niall Douglas via Boost a écrit :
>>> 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.
You are right it is moving and not yet accepted.
One of the major interest I have in this review is to try to see what
can be improved on the proposed std 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.
I understand you.
> 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.
Okay. Has this clearly stated and showed throw examples in the
documentation? Sorry, I have not read all the documentation yet.
IIUC, what you want is to have outcomes that copy/move well each one on
each other. Is this the major drawback you find to the use of
std::expected and std::optional?
> 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.
I recognize there is a problem when we need to forwarding errors that
are transformed.
This is my TODO plan for the standard proposals. Maybe my approach would
be what you consider is the way we shouldn't follow. We will see.
> 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.
This transformation can be hidden by higher level abstractions, but IMO
they should be invoked explicitly.
> I will claim that if you *are* building such an interop framework, you
> will find that Outcome is the bare minimum implementation possible.
Maybe or maybe not. If outcome uses more storage than expected or
optional it is not the base minimum.
> 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.
Niall sorry, I don't like the worlds "universal" and similar
qualifications as "ultra-lightweight error handling" and "minimum
overhead universal outcome transport mechanism for C++"
To what other "universal error handling are you referring?
Ho wis your design universal?
> Outcome doesn't do any of that, it never allocates memory, has highly
> predictable latency,
I hope so :)
> runs perfectly with C++ exceptions disabled,
This is an interesting point. I will add it to the goal of your library.
What is the behavior on the absence of exception on the functions that
throw exceptions? Are these functions disabled? Does the fucntion
terminate? Calls a handler?
> is an
> excellent neighbour to all other C++ libraries
as for example?
> AND build systems,
I'm less concerned by the build systems, but could you elaborate?
> 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.
It is not imposing the use of boost::outcome?
Does it interact well with std::expected and std::optional and
boost::optional?
I see that you responded in another mail No.
> 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 must recognize I'm reluctant to the basic_monad abstraction, and of
course if the library is accepted should change of name.
I'll need to take a deeper look, but I don't know if we are reviewing
basic_monad it or if it is there by accident?
> I'll respond to your other comments in a separate reply. I just needed
> to unload the above,

I understand.
> 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.
If the main goal is the universal error handling strategies, then the
documentation must describe what this is?
> (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)
>
Could you tell us which example?

Best,
Vicente


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