Subject: Re: [boost] Outcome/expected/etc/etc/etc
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-06-06 08:31:47
2017-06-05 20:05 GMT+02:00 Niall Douglas via Boost <boost_at_[hidden]>:
> On 05/06/2017 15:23, Gottlob Frege via Boost wrote:
> > On Mon, Jun 5, 2017 at 7:57 AM, Peter Dimov via Boost
> > <boost_at_[hidden]> wrote:
> >> Gottlob Frege wrote:
> >>> Some days I'm like "man just accept empty, it would be a simple API",
> >>> then I think "it is stupid for variant<int, double> to be empty".
> Other days
> >>> I think "just double buffer when necessary" (I assume that's your
> >>> Peter?), but then I think "I don't want double-buffering variant<list,
> >>> vector> to go on/off based on whether I use MS std vs libc++ etc" and
> >>> "I don't want double buffering for cases that only happen in theory,
> not in
> >>> practice".
> >> That is my direction, yes. My variant uses double storage when (1) not
> >> types have noexcept move constructors and (2) there isn't a noexcept
> >> constructible type in the list.
> > So converting a Circle to a Triangle might result in a Rectangle,
> > because Rectangle is the fallback?
> > I'd rather have double buffering or valueless_by_exception. ie
> > correctness or acknowledgement of error. Not silent incorrectness.
> 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 restore.
> 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.
What `variant2` could do is to provide one (out of a number of)
specialization of using it in a way where it gets the guarantee that at
most one type has a potentially throwing move, and in exchange it
1. You get strong guarantee.
2. You get no double-buffering.