Boost logo

Boost :

Subject: Re: [boost] [review] Review of Outcome v2 (Fri-19-Jan to Sun-28-Jan, 2018)
From: Emil Dotchevski (emildotchevski_at_[hidden])
Date: 2018-01-31 21:21:06


On Wed, Jan 31, 2018 at 3:53 AM, Andrzej Krzemienski via Boost <
boost_at_[hidden]> wrote:

> 2018-01-30 22:07 GMT+01:00 Emil Dotchevski via Boost <
> boost_at_[hidden]>
> :
>
> > This is my review of Outcome v2.
> >
> > Further, I disagree with the motivation to avoid using exceptions to
> begin
> > with. The supplied decision matrix, I think, does not reflect reality. In
> > my experience, the decision matrix to use C++ exceptions vs. something
> else
> > is much simpler: "Do you hate exceptions?" No => use exceptions, Yes =>
> use
> > something else, because exceptions suck.
> >
> > Yes, exception handling has overhead. No, you can't afford this overhead
> in
> > every last corner of a complex program, but yes, you can afford it in
> > general. I have had many discussions on this and other "but but but
> > Overhead" topics, and I have never been given actual evidence that any
> > given program that does not use exceptions to report errors could not be
> > written using exceptions to report errors, without sacrificing
> performance.
> > And this is trivially true: if exception handling causes problems in some
> > subsystem, the solution is to hide that subsystem behind a C-style API
> and
> > compile only that subsystem with exception handling disabled.
> >
> > So, the design of "an error handling library that does not use C++
> > exceptions" has to target the tricky bits where exceptions would be
> > annoying or can't be used, not the general case where they can.
> >
> > Finally, I'll point out that a lot of the positive feedback comes from
> > people who think that it is a good idea to replicate the Rust error
> > reporting mechanism in C++. This seems to be an axiomatic belief, since
> > I've never seen anyone attempt to substantiate it. This is important, as
> it
> > is typical for programmers coming from other languages to be shocked by
> > various C++ language features, and this should not be confused with
> > problems in the C++ language specification.
> >
>
> I feel I need to respond to this. My remarks are only to this single
> argument about the superiority of exceptions -- not to the review and other
> arguments.
>
> Because you say this in the context of Boost.Outcome review it sounds a bit
> as if you were saying "I am against Boost.Outcome, because exceptions
> should be preferred to any other failure handling mechanisms". I do not
> know if you are really saying this, but this is the impression I get.
> Please correct me if I am wrong.
>

No, I am not against Outcome, I'm against Outcome being part of Boost.

> While the introduction to docs mentions "The high relative cost of throwing
> and catching a C++ exception", it also lists other use cases that are not
> related to performance. Are you also questioning other motivations for
> using this library?
>

Let's address the rest of the enumerated use cases one at a time:

- Making some or all control paths explicitly detailed to aid code
correctness auditing, as opposed to having hidden control paths caused by
exceptions potentially thrown from any place.

This is one of these axiomatic beliefs that need to be substantiated
instead. It is simply not true that code that uses exception handling
("hidden control paths") is more difficult to audit or more prone to
errors. In my experience it's the other way around: people who don't use
exceptions are not serious about error handling; they're the ones who also
need advanced logging libraries to help them figure out what went wrong
_this_ time around.

- Company policy to compile with exceptions disabled.
- Maintaining a code base that was never designed with exception-safety in
mind.
- Parts of the programs/frameworks that themselves implement exception
handling and cannot afford to use exceptions, like propagating failure
reports across threads, tasks, fibers…

These are valid use cases, however this is not the main focus of Outcome.

A library designed for maintetance of legacy code and interoperability
can't assume that you can always change existing functions to return a
result<T>, much less the complex policy-based types in Outcome. Such a
library should be able to propagate errors through ucooperative layers of a
complex code base. In my biased opinion, (Boost) Noexcept is a much better
tool for this use case; see this example which propagates errors from C++
through the Lua interpreter (which obviously doesn't know about Noexcept)
back into C++: https://zajo.github.io/boost-noexcept/#example_lua.

Another important feature that facilitates interoperability is the ability
to forward to the caller arbitrary errors that originate in lower level
libraries, the way throw without argument does in case of exceptions. This
is contrary to Outcome's insistance of specifying the error type for
result<T>. This design decision leads to the following class of problems:
what do you do if you've said you can only return errors of type E1, but a
low level library or a callback function returns an error of type E2? The
only solution is to translate. Incidentally, check out how well this
solution works with exception specifications. :)

>
> Exceptions play well in the most common situation where failure to execute
> some instruction `x` should prevent the execution of the subsequent
> instruction.

Yes, enforcing postconditions.

> If this is not the case, exceptions just add mess compared to
> manual control flows. This is not limited to C callbacks. I had similar
> problems inside a task framework.
>

Agreed, but Outcome is not a good solution to this problem because it
doesn't erase the type of the stored error object. You couldn't store
outcome::result<T,E1> and outcome::result<T,E2> in a vector (but you could
store noexcept_::result<T> in a vector, see
https://zajo.github.io/boost-noexcept/#example_threads.)

Rather than solve this difficult problem, Outcome pushes it to the user to
solve, in that the user has to come up with an error type that can store
any error -- or translate between different error types, which is worse,
this is the stuff exception specifications are made of.

> And you are actually saying the same thing. Except that somewhere you
> appear to arrive at the conclusion that this library should be rejected
> because of being alternative to exceptions. And I cannot understand this.
>

My objection is that the main focus of Outcome is to solve a problem that
does not exist. It's like using modern tech to create a great typewriter,
with the added benefit of a free eraser pencil in the form of OUTCOME_TRY.
:)

> And I note that I am not familiar with Rust. My motivation for using this
> library is that I have observed places in my programs where exceptions just
> make the flow more complicated, and I needed to use something else so that
> the code reflects my intentions more directly, and Boost.Outcome addresses
> those issues.
>

I'm not against you using Outcome.

Emil


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