Subject: Re: [boost] [outcome] How to drop the formal empty state
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-26 12:50:41
>> This is precisely why I added a formal empty state, and default
>> initialised to that. Because it causes behaviour different to valued or
>> errored, it **very** effectively traps logic errors during code
>> development. On **many** occasions it has successfully illuminated
>> poorly thought through code that I have written by bringing to my
>> attention - early and very obviously - that someone was very wrong. I am
>> absolutely convinced it is a great design choice.
> My worry with the formal empty state is precisely that as neither a
> value nor an error, someone might fail to check for it in code and then
> proceed under a false assumption. (If not has_error() then this void
> method must have succeeded, and I don't call value() because it was void.)
> Provided that .value() and .error() both throw if called in the empty
> state (which I assume is the case), that helps mitigate a large part of
> that, but not entirely, as in the case above.
Both do throw on empty, yes. The only other time Outcomes throw is on
.value() where the state is errored, in this case we throw the error
directly if it's excepted or the error code wrapped into std::system_error.
Regarding the danger of proceeding under a false assumption, it can't
happen if users never create an empty outcome because outcomes don't
suddenly turn empty on their own, so if you never create one, you'll
never get one.
That's why I think the formal empty state is safe. If you never create
an empty outcome, you can safely totally ignore empty as a possible
state. It will *NEVER* happen.
> Yes, it's a misuse of the type, but it's one that I can see being very
> likely to happen in the real world. Even if the possibility of an empty
> state is heralded with bold blinking all-caps on all doc pages.
I think the docs does need to emphasise that if you never create an
empty outcome, you can safely ignore ever dealing with the empty state.
>> I'd therefore be happier with default construction giving uninitialised
>> contents, or a default constructed T or E. No overloading state of E.
> I do like the idea of a non-default-constructed error code, because
> failure to initialise the result does seem like an error to me. Niall
> points out that this is harder to detect and treat specially in code but
> I don't agree with that; as long as a suitably unique error code is used
> then a simple assert in the error path would pick it up, no problem.
I am strongly opposed to this design. It conflates logic errors in the
code design with runtime errors. It's a bad design choice.
> If the consensus is that an initial non-default error code is not
> satisfactory, then a formal empty state seems to me like the least worst
> alternative. I just know that it's going to bite someone at some point.
I have been persuaded by argument here that default construction to
empty is in fact a defect in the design. The formal empty state ought to
*always* be explicitly constructed, and **never** occur implicitly. I
have logged this defect to https://github.com/ned14/boost.outcome/issues/44.
Still another option is that if T has a default constructor, we default
construct to a T instance, and if T does not have a default constructor,
we implement no default constructor. This is what Expected already does
incidentally. Outcome could do the same.
-- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk