Subject: Re: [boost] [variant2] Andrzej's review -- design
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2019-04-03 07:53:53
År., 3 kwi 2019 o 01:33 Gavin Lambert via Boost <boost_at_[hidden]>
> On 3/04/2019 05:27, Andrzej Krzemienski wrote:
> > This is not a full review yet. I just wanted to discuss the design first,
> > especially the never-empty guarantee. And I am going to rehash the old
> > argument.
> > The core of variant2 is its never-empty guarantee and the mechanism to
> > achieve it: a number of different algorithms chosen depending on what the
> > potentially stored types permit. In fact this mechanism is not much
> > different than the one present in boost::variant.
> I agree with most of the points that Andrzej has made, although I would
> go a step further and question why people want a never-empty variant in
> the first place.
> There is always potential uncertainty about the actual content type of a
> variant, requiring either assumptions (and UB or exceptions if wrong) or
> explicitly testing, eg. with visit. Checking if a variant is empty
> seems no different to me than checking if it contains an int; eliding
> either check confers exactly the same risks.
> Requiring that variants always possess an empty state dramatically
> simplifies implementation, including default construction and move
> assignment. And it avoids the valueless_by_exception kludge by
> promoting it to an entirely expected possible state of variant.
> (Thereby increasing the chance that consumers will consider it.)
> It also means that (like traditional monads), variant<T> is behaviorally
> equivalent (bar some naming conventions) to optional<T>, which seems
> like a consistent conceptual choice. And variant<> is valid and can
> only hold the empty state.
In principle, the stronger the invariant, the fewer opportunities to make
bug. The strive for never-empty variant is conceptually similar to a strive
for a pointer that does not have the null-pointer state. We often give
advice to people that as long as this is possible you should prefer using
references to using pointers, because the former do not have the null
state. The significant portion of crashes in the programs I have worked
with was when a null pointer was dereferenced. Function f() returns a
shared_ptr<> and the implied contract is, it is not null. I do not want to
check for null pointer whenever I use it. But at some point some clever
developer comes to an idea that if he doesn't know what to do, he will
return a null pointer. These problems would not happen if there was a type
never_null_shared_ptr. It just wipes a class of bugs from existence.
I am myself in favor of never-empty guarantee for variant, as long as it
does not cost too much. The notion of how easy/hard it is to implement
something should not drive the interface and the contract of a type. I
object to the never-empty guarantee for variant because it costs too much
and affects the contract of the type. In C++ performance characteristics of
a type are part of its contract.
> Furthermore, while I can see possible value in a never-empty
> strong-guarantee variant (although I remain unconvinced that the
> "never-empty" part provides much benefit, as above); as soon as this
> guarantee is weakened then I don't see any advantage at all in trying to
> maintain a "never-empty" property. Unexpectedly changing type and/or
> content is exactly as bad as unexpectedly becoming empty.
> Unsubscribe & other changes:
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk