Subject: Re: [boost] [outcome] To variant, or not to variant?
From: Peter Dimov (lists_at_[hidden])
Date: 2017-06-02 16:55:07


Andrzej Krzemienski wrote:
> >> > That's what I was thinking - that you want to place an assert there -
> >> > I just wanted to confirm that this is the only objection.
> >>
> >> It is not _the only_ objection. I thought that this one would be the
> >> easiest to communicate across.
> >>
> >
> > What are the others?
>
> In code reviews, when I see someone using the function out of contract, I
> know that this someone has a bug.

But this doesn't apply here, does it?

When you see r->x for !r, you do know that someone has a bug, right?

> > vector::operator[] accesses occur in tight inner loops, the check is
> > hard to optimize out, so we swallow the UB. Doesn't mean we have to like
> > it, it's a necessary evil here.
>
> Should I read the above as saying that in case of vector it would cause
> too much potential run-time overhead;

Not merely potential. Actual slowdown on the order of 100. You should read
it as "as much as we'd like to define the behavior of operator[], doing so
would be prohibitively expensive, so we won't."

> > > The root of our disagreement is the idea that undefined behavior is
> > > good because it supposedly allows you to do this or that.
> >>
> >> It is not in this that I see the root of our disagreement. In fact, I
> >> do not yet see where this root is. What I fight for is not an UB but
> >> narrow contracts.
> >>
> >
> > Traditionally the two are synonyms in C++. If you have a narrow
> > contract, the behavior on contract violation is undefined. Can't have
> > one without the other.
>
> Maybe this calls for a new kind of precondition specification: that
> calling a function in given circumstances is formally incorrect (tools are
> allowed to make use of this information), but the component still
> guarantees a rescue action.

That's kind of what we all want, but there's at present no way of getting
there. Ideally -- let's assume we don't want to allow uses of the form
`r.operator->()` -- we would want `operator->` when `!r` to either invoke a
precondition violation handler that is guaranteed to terminate the program
and never return, or to return `nullptr`.

We have no tradition in expressing the above, so within the current
vocabulary I prefer guaranteeing the `nullptr` instead of leaving the
behavior undefined in the hope that it will end up being defined to the
above. (It won't be.)