Subject: Re: [boost] variant2 never empty guarantees (was: Re: Outcome/expected/etc/etc/etc)
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-06-06 09:29:18
2017-06-06 11:15 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:
> >> I hate with a passion any possibility of a variant changing its state
> >> without me explicitly telling it to do so. The only tolerable state a
> >> variant should ever choose on its own is empty/valueless.
> >> I repeat my suggestion that for variant2:
> >> 1. If at least all types minus one have nothrow move construction, you
> >> get the strongest possible never empty never change guarantee.
> >> 2. If the user is dumb enough to supply more than one type with a
> >> throwing move constructor, they get the current C++ 17 variant valueless
> >> by exception semantics i.e. go valueless if changing state threw an
> >> exception and the previous state threw an exception on attempt to
> >> 3. We thus never double storage.
> >> 4. And we never, EVER change state silently to something the user did
> >> not explicitly ask for.
> > I would recommend not mixing the design discussion of `variant2` with the
> > design considerations of `outcome`. `outcome` has its own design
> > constraints: it is natural to have only one type with a potentially
> > throwing move constructor. In contrast, `variant2<Ts...>` cannot make any
> > assumptions or guesses about `Ts...`, so it may need different
> > implementation of the assignment.
> I am not mixing the design discussion. I am talking about variant2 only.
> I am proposing the above mix of strong never-empty never-change
> guarantees when the user supplies a reasonable set of types. So:
> 1. If all but one of the types has a nothrow move constructor, you get
> the strong never-empty never-change guarantee.
> 2. If more than one of the types has a throwing move constructor,
> assignment still moves old state onto the stack before attempting to set
> new state. If, *and only if*, **both** the move of the new state throws
> and the attempt to restore the old state ALSO throws, then and only then
> do we enter valueless-by-exception state.
> My view here is that C++ 17 std::variant already has
> valueless_by_exception(). My proposal is that it becomes a very rare
> situation indeed to ever occur, and guaranteed not to occur if the types
> supplied meet the conditions requested.
> End user code can test if the never empty guarantee is in place using
> 'if constexpr(!variant.valueless_by_exception()) ...' because bool
> valueless_by_exception() would become constexpr false in the
> implementation with the strong never empty guarantee.
You are basically saying: provide the implementation that gives me strong
guarantee when I meet condition X. ("X" being up to one type with
potentially throwing move constructor).
Your expectation is reasonable, but (I think) it is incompatible with other
peoples' expectation: provide implementation that gives me never-empty
guarantee when I meet condition Y. ("Y" in that case means I have a type
with nothrow default constructor.)
I do not think both expectations can be satisfied in one implementation.