
On Wed, Jan 31, 2018 at 3:53 AM, Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
2018-01-30 22:07 GMT+01:00 Emil Dotchevski via Boost < boost@lists.boost.org> :
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
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