$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [review] Review of Outcome v2 (Fri-19-Jan to Sun-28-Jan, 2018)
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2018-02-02 01:29:26
On 1/02/2018 19:55, Emil Dotchevski wrote:
> This does not protect the user at all:
> 
> std::unique_ptr<A> a=A::create();
> a->foo(); //undefined behavior
Sure, but you can always write daft code.  If you are aware that it is 
legal for A::create() to return nullptr (and you should be aware, 
because it will be documented), then the above would be an obvious bug, 
and you should replace it with:
     if (auto a = A::create())
     {
         a->foo();
     }
This is *much* more obviously safe than your suggested exception-enabled 
code, where you have to have external knowledge (that it will throw on 
failure and cannot ever return nullptr).  And it's trivial to add logic 
for the failure case in an else block, vs. the more wordy try-catch.
(Even if you don't know whether A::create() is supposed to be able to 
return nullptr or not, it is usually more sensible to defensively write 
the code as if it could, since it is a legal value of the return type, 
regardless of whether exceptions are enabled or not.)
Granted, exceptions are better at telling you *why* it failed, which the 
above can't.  And exceptions are better at hiding the error-handling 
paths for the cases where errors are expected to be exceptionally rare 
(pun intended), which can make the "real" logic not get lost in a maze 
of error-handling.  Most people appreciate that -- but sometimes having 
explicit error paths is useful too.
Nobody is forcing you to stop using exceptions, or even encouraging the 
majority of applications to stop using them.  Outcome just provides a 
way to add back a little (or a lot, as needed) explanation to failure in 
cases where someone has already decided they can't or don't want to use 
exceptions for whatever reason -- especially when failure is expected, 
not unusual (I think everybody agrees that exceptions-as-control-flow is 
not good code design, right?).
> This is not an advantage over using exceptions, and besides it is only true
> in the simplest of cases. The problem is that Outcome requires users to fit
> any and all possible failures into a single error type, which is not always
> possible. In general, you can neither enumerate nor reason about all
> failures which may occur. Notably, the one Outcome feature that can deal
> with this problem is its ability to transport std::exception_ptr. :)
One error type per context.  You can have completely different error 
enumerations per method if you really want to, although it would 
probably be more common to have one error domain per library, or just 
use the closest approximation from a standard set, like POSIX errno.  Or 
use error_code, which allows relatively seamless interoperation with all 
of these.
Exceptions are actually a relatively poor method for transporting errors 
that need to be *reacted* to.  (Not so much through any fault of 
exceptions themselves, but rather through common usage thereof.)
In most code, the best you can do with them is catch them in some 
central place and log them for some developer to look at later.  Too 
many methods just throw one of the standard types like 
std::runtime_error without defining custom subclasses or adding anything 
more programmatically useful beyond the text message -- which in itself 
can be a problem for multi-lingual applications, especially where the 
thread that generated the exception is running in a different language 
context from the developer and/or user.
At least an error code is inherently an abstract thing that you know you 
need to look up a translation for at the last moment when actually 
presenting it to the user, or that logic can easily say "in this 
context, I was expecting that and I know how to deal with it".
Sure, it's possible to add error codes and extra data fields to 
exceptions and allow the message to be constructed later from these 
pieces.  And it's not possible to do this with error_code alone.  But it 
will be possible to do this with Outcome.  (And most people don't do it 
anyway, no matter the error transport.)