4

This topic is controversial, but I'm in the camp which believes that preconditions and class invariants should be guarded by asserts which terminate the program if the contract of the corresponding SW component is violated - as long as the runtime cost for the assertion checks is not a performance bottleneck.

I really like optional types and use them a lot, but for me the standard library implementations of std::optional are unusable as of now, since first the dereferencing of an optional does not perform checks whether it contains a value, and second none of the major c++ implementations support/implement assertions within standard library functions as of now.

From the use of std::optional I have seen over the years, I cannot recall a single instance where a std::optional was used in such a manner and quantity, such that precondition checks would be a performance bottleneck and prohibitive. For instance, I have never seen that somebody implemented a mask image as an array of std:optional's.

My question: Is there any proposal out already (e.g. for c++22), which adds contract features to the standard library, in particular std::optional?


Yes, I'm aware of the value method which is "guarded" by an exception. First, I'm not a big fan of non-exceptional control flow using exceptions (have you ever tried to debug such code). Second, I believe the strength and safety of a type should judged by its weakest link.


I can't comment yet, hence I comment on the answer by Nicol Bolas here:

Thanks for the answer, but I frankly I don't think it answers my question. Just to clarify. I'm not asking for a proposal which mandates that std::abort is called on contract violations (of an "expect" close). Instead, I'm asking whether there are any plans to add contract annotations to the standard library following the P0788 proposal. I agree that the standard should not mandate how specific implementations should deal with such contract violations.

B0rk4
  • 241
  • 1
  • 9
  • "*Is there any proposal out already (e.g. for c++22), which adds design by contract support to the standard library, in particular std::optional?*" That's kind of distinct from the entire rest of your question, because Contracts *does not* do what you said you wanted. Specifically, it guarantees *nothing* about terminating the program if the contract is violated. Yes, *you* can compile *your code* such that contracts will be checked and the program terminated if they fail, but there's no guarantee that other people will. – Nicol Bolas Jul 14 '19 at 17:26
  • @NicolBolas That is fine. I only want to support those folks who decided to have terminations when the contract is violated. However, this is currently not possible. Sure, others decide to never terminate on assertions and detect UB in different ways (e.g. using adress sanatizers etc.), why would I want to interfere? – B0rk4 Jul 14 '19 at 17:32
  • Doh.@NicolBolas good catch. That was a typo. "assert" -> "exception". – B0rk4 Jul 14 '19 at 17:34
  • 1
    I don't have a handy link, but I had heard of Plauger of Dinkumware having created a "safe" (opt-in, for non-release code) version of the standard library to help figure out bugs. But that's not quite the same if you want that to be in your release binary. – Eljay Jul 14 '19 at 17:34
  • @Eljay yes, there is clearly a gap. A lot of companies and open source projects use "std::abort"-like asserts in their production code (or at least in optimized pre-production code a la RelWithDebInfo). Only the main standard library implementations do not support such feature, which is a shame. – B0rk4 Jul 14 '19 at 17:37
  • "How 'exceptional' it is for a particular optional access is determined by the user, which is why there's a version that throws. If someone considers it 'exceptional', they can use the API that decides that it is exceptional." @NicolBolas Following that train of thought, I'd say one would need two types (std::optional and "std::exceptional"), instead of defining an all-in-one compromise type. – B0rk4 Jul 14 '19 at 17:54
  • 1
    @B0rk4: "*Following that train of thought, I'd say one would need two types (std::optional and "std::exceptional"), instead of defining an all-in-one compromise type.*" Um, why? The types would be identical in every way *except* for how `operator*` works. It would lead to a pointless proliferation of types, resulting in people *forcing* one mode of behavior on others by picking the type that uses the mechanism they would rather use, and giving the receiver of the type no recourse to use their preferred tool (if any). C++ is not a safe language. – Nicol Bolas Jul 14 '19 at 18:24
  • 1
    @B0rk4: "*I frankly I don't think it answers my question*" But it does answer your question. I even *quoted* your question as I answered it. You asked if the contracts feature (which you equated with "design by contract", an equation that I would disagree with, but that is how you seem to see it) was going to be applied to the standard library. And the answer was not just that this hadn't been considered, but that it was considered and *rejected* as part of the standard. That is, P0788's adoption *explicitly* rules it out. It doesn't get more "no" than that. – Nicol Bolas Jul 14 '19 at 18:54
  • @NicolBolas, thanks for the discussion. It is rather insightful. Let me first reiterate over my question and rename terms such they are closer to terms in the standard. I'm not married to "design by contract" etc. – B0rk4 Jul 14 '19 at 19:35
  • @B0rk4: ... your edits only make my answer more correct. Read the quote from P0788: "Let’s avoid **any specification** that demands ***any particular technology*** by which implementations must comply with Library specifications." Emphasis added. `expects` (renamed `pre`) would be "any particular technology", so no. If you're asking if the standards committee has decided to *reverse* the decision they *just made* on this? Probably not. – Nicol Bolas Jul 14 '19 at 22:47

2 Answers2

11

This is kind of moot for the immediate future, since contracts was removed from C++20 for some reworking. However, I think the remaining text still applies:

Is there any proposal out already (e.g. for c++22), which adds design by contract support to the standard library, in particular std::optional?

Quite the opposite: the proposal P0788 was adopted and folded into the C++20 working paper, which states that preconditions/postconditions are not to be mandated to be implemented by the contract feature. The specific intent of P0788 was to prevent formalized requirements on implementations to use contracts for these things (or concepts for similar conditions):

Let’s avoid any specification that demands any particular technology by which implementations must comply with Library specifications.

Implementations are permitted to express such conditions as contracts, but are not required to. By adopting P0788, the committee is effectively considering such things to be a matter of implementation quality, not formal specification.

C++ is not a safe language, and contracts are not intended to make it so. Violating contracts is a programming error and yields UB, and that's how the standard sees things. And by design, there is no way for you to force your desire for safety upon those who don't want it.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

Answer to my own question. Thanks for the discussion which pointed in the right direction.

Currently, the dereference operator of std::optional is annotated with an "Requires" clause.

In the spirit of P0788, I'd expect the Requires clause to be changed to Expects in the near future:

Let’s make it a goal, over time, to eliminate all Requires: elements from our Library specifications, preferring our new elements instead.

Furthermore, standard library implementations are permitted to any technology to meet "Expects" specifications.

  1. Let’s permit an implementation to use Contracts attributes [P0542R1] and/or any other technologies to meet Expects: and Ensures: specifications.

So far, so good. Only the following statement makes it a little more tricky:

  1. Let’s consider user code that relies on any specific technology on the part of an implementation to be ill-formed, with no diagnostic required

My interpretation of the above that users can't rely that standard implementations will guard Expects in any specific way or at all, but they may.

To the question:

Is there any proposal out already (e.g. for c++22), which adds contract features to the standard library, in particular std::optional?

Yes, contract annotations are already part of the standard.

It is up to the specific library implementation how to deal with "expect" clauses.

B0rk4
  • 241
  • 1
  • 9
  • 2
    "*Yes, contract annotations are already part of the standard.*" But... that doesn't add anything to the standard. Saying that it may happen doesn't add anything, because implementations were free to do that *anyway*. Undefined behavior is undefined. Imagine someone asks if there is a proposal for C++17 that adds 2's complement integers, and someone says "yes, implementations can make signed integers 2's complement". But if implementations aren't *required* to provide 2's complement, the fact that they *could* be used is utterly meaningless. Which is why C++20 provides a guarantee there. – Nicol Bolas Jul 14 '19 at 22:53