Subject: Re: [boost] [outcome] To variant, or not to variant?
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-06-02 17:08:39
2017-06-02 18:55 GMT+02:00 Peter Dimov via Boost <boost_at_[hidden]>:
> 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?
Yes, do. I am giving you the second reason why I want the narrow contract.
Within this second reason, I can live with your semantics. But previously I
have given you other reason, and there the operator-> trick will not work.
> > 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."
Why the same argument with "compiler will see that I am checking the same
condition twice, and remove redundant checks" does not apply here?
> > > 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`.
Actually, now I am thinking not about Boost.Outcome but specifying these
preconditions in the Standard. If you want to std::terminate upon some
condition rather than let the program do random things, you could say.
*Requires:* `!r` with rescue action `std::terminate()`.
> 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.)
That is true, "it wont' be". And that was never the goal.
But what is the gain with the nullptr trick? someone can still cause UB
with it, so it does not seem much "safer". Are you increasing the chances
that it will be trapped by the operating system?