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-02-01 06:55:48


On Wed, Jan 31, 2018 at 10:30 PM, Gavin Lambert via Boost <
boost_at_[hidden]> wrote:

> On 1/02/2018 19:09, Emil Dotchevski wrote:
>
>> The factory method technique also allows somewhat restoring a stronger
>>> invariant -- only the constructor and destructor need to cope with empty
>>> or
>>> otherwise uninitialised instances; other methods can be reasonably
>>> assured
>>> that no such instances escaped the factory method.
>>>
>>
>> This is true only if you use exceptions to report errors from the factory.
>> Otherwise it is most definitely NOT reasonable for member functions to
>> assume that the object has been initialized, because nothing guarantees
>> that an error reported by the factory wasn't ignored.
>>
>
> The factory itself provides that guarantee. One such pseudo-code
> implementation might be:
>
> static std::unique_ptr<A> A::create(args...) noexcept
> {
> // the constructor is itself noexcept and cannot fail
> std::unique_ptr<A> a(new (std::nothrow) A(arg1));
> if (!a)
> return nullptr;
>
> if (!a->private_init_stuff(arg2, arg3, ...))
> return nullptr;
>
> return a;
> }
>

This does not protect the user at all:

std::unique_ptr<A> a=A::create();
a->foo(); //undefined behavior

Compare to:

static std::unique_ptr<A> A::create(args...)
{
  std::unique_ptr<A> a(new A(arg1)); //new throws on error, A::A() throws
on error
  return a;
}

And then:

std::unique_ptr<A> a=A::create();
a->foo(); //Okay, a is guaranteed to be valid.

Once again, you'll notice that if you use exceptions, the compiler "writes"
the correct error checks for you, and the user is automatically protected.

With Boost.Outcome, it can be implemented exactly as above (including not
> letting an invalid instance escape), but *also* indicate a failure reason
> to the caller, through a simple change to the return type.
>

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. :)

> Are exceptions cleaner and shorter? Of course. But this still works, and
> some people will prefer it due to perceived latency issues with exceptions,
> or just personal issues with exceptions in general, or with "hidden code
> paths" expressly due to the code being shorter. (Whether those issues are
> real or not, I cannot say.)

Well, I can. :)

Emil


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