Subject: [boost] [variant2] Andrzej's review -- design
From: Mike (mike.dev_at_[hidden])
Date: 2019-04-03 09:08:11
I have to say that I'm with Andrzej on this matter.
Mabye I'm blind, but it seems to me that people repeatedly mix up
"never empty" and "no error state".
Variant2 can still get into an error state, just that that error state is not
explicitly named and modeled as part of variant2, but instead, a "regular"
state is reused to signal that error:
Either monostate or whatever is the first type that has a non throwing
default constructor. It is only if neither of those options is available that
variant2 falls back to double buffering and does actually avoid ending up in
an error state at all.
Also, I don't see the problem with valueless_by_exception. Other than nullptr,
you don't have to explicitly check for it most of the time (at least not more
often than you'd have to check for monostate in variant2). Consider what
you can do with a variant:
- get: If you are guessing the current type wrong, you get an exception
Doesn't matter if the actual type is valueless_by_exception or just
an unexpected regular type.
- get_if: Again, if you are guessing wrong, you get a nullptr
- copy/move: valueless again behaves just like another type
- index: Valueless just returns a unique index. The only special thing about it
is that it doesn't fall into the regular range between zero and the
number of member types.
- comparison operators: valueless_by_exception is even more convenient,
because you don't have to check first if the left and
right hand side are of the same type,
but you can still treat it just as any other T if
- visit: This is the only case where valueless is really special: You get an
exception instead of having to provide an overload for e.g. monostate.
Considering how rarely a variant ends up in such a state, throwing
an exception is imho the right thing to do most of the time anyway
(use an exception to report exceptional errors). But when that is not
appropriate, then yes, you have to either check beforehand or catch
the exception instead of building the logic into your visitor.
Of course I can imagine a scenario, where one or the other approach
is simpler, but 99% of the time it really doesn't make a big difference.
What I'm trying to say here is not that the design of std::variant is better than
boost::variant2, but that they are just two different design choices that may be
more or less convenient in a particular scenario, but overall don't make a big
difference one way or the other.
What I personally do find a bit problematic is that variant2 would be yet another
variant type that is not completely compatible to std::variant, without providing
significant benefits or a fundamentally different design (e.g. providing strong
exception guarantee or dramatically improved compile-time or run-time
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk