Boost logo

Boost :

Subject: Re: [boost] [variant2] Need rationale for never-empty guarantee
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2019-03-01 13:07:31

Hi Niall,
Thanks for the response. But I must admit I do not fully understand what
you are saying.

pt., 1 mar 2019 o 11:14 Niall Douglas via Boost <boost_at_[hidden]>

> > The guarantee provided by variant's assignment is not a strong exception
> > safety guarantee: it is possible that my variant has value A, I want to
> > assign value B, and (due to an exception) I end up with value C. If this
> > happens, the only thing I can reasonably do is to either abandon
> whatever I
> > was doing or reset the variant to the state that I need. So the guarantee
> > that it is not left empty does not seem to be of much use. But the cost
> to
> > be paid is noticeable.
> I would disagree with this assessment of the strong never empty
> guarantee provided by variant2.

Do you disagree with the observation that you can get to state C when you
wanted to move from state A to state B? Or do you disagree with the
statement that variant2 does not provide strong exception safety guarantee?
Or do you disagree with my judgement that the never empty guarantee is not
of much use?

> I have only seen a certain amount of std::variant being used in the
> wild, written by average C++ developers. In every such case, however, I
> have never seen any accounting for the possibility of the std::variant
> being valueless, despite that the codebase does throw exceptions, and
> that the std::variant is not in temporary storage duration.

Would it be possible for you to give a short invented example that would
illustrate what you are saying? or is it something like this:

std::variant<A, B, C> global_variant;

void f()
  try { global_variant = B{}; } catch(...) {}
  // ...
  // now do a visitation on variant
I agree that this is how you could observe the valueless state. But I also
claim that such code (I wait to be convinced otherwise) has already more
serious problems than observing the valueless state on variant. You
typically do not want your objects to outlive the stack unwinding. And if
you do, for globals, you want to provide a transactional-like guarantee.
Leaving such objects in "valid but unspecified states" is a design bug.

Or am I wrong?

> I find that to be a code smell.

I find it a code smell when you leave global objects in a "valid but
unspecified state; whether they are variants or anything else.

In the code I have written myself where
> I used std::variant, I know it will be later modified by programmers who
> may not account for valueless.

If you used variant (which does not provide a transactional exception
safety guarantee) in situations where an exception is thrown when modifying
the variant's alternative and the variant outlived the stack unwinding and
you were still trying to read it and you considered this a good design,
then I would like to be shown such example.

I therefore have always wrapped my use of
> std::variant with valueless handling code, even if it isn't needed right
> now, in order account for the future possibility that someone might add
> a type which can throw during move or copy. It also reminds later
> programmers about valueless, so it is self documenting.

My position (until I see examples that will convince me otherwise) is that
if a programmer observes the valueless state in a variant, then the
programmer is doing something wrong with handling exceptions.

> This, in my opinion, is exactly the situation which so many people
> objected to WG21 regarding the possibility of valueless at all in
> std::variant. It introduces a corner case which few will consider, and
> it is certainly virtually untestable, so anyone sensible is going to
> wrap every std::variant with a wrapper to handle valueless.
> I find that situation daft. And it was completely avoidable.
> For me, a HUGE tick in favour of variant2 is that it has the design
> which std::variant should have had from the beginning, at little build
> time nor runtime cost over std::variant.
> I will therefore be strongly recommending the use of variant2 instead of
> std::variant wherever possible. Until WG21 clean up that mess, which I
> hope variant2 will help persuade them to do.

You are contrasting boost::variant2 with std::variant, but the design space
I see is more than just either of them. If std::variant is wrong (which I
tend to agree with) it does not immediately imply that boost::variant2is
right. Another alternative that Peter indirectly suggested is that it is UB
if you try to observe the valuelsess state in std::variant. In this case
some usages after a throw are banned, but the model still guarantees the
never emptiness.


Boost list run by bdawes at, gregod at, cpdaniel at, john at