# Adding a global contract assumption mode

P1786R0

Published: 2019-06-17

Authors:
Hyman Rosen (hrosen4@bloomberg.net)
John Lakos (jlakos@bloomberg.net)
Alisdair Meredith (ameredith1@bloomberg.net)



## Abstract

This paper proposes adding a global contract assumption mode, in order to
permit the addition of contracts without affecting the behavior of code that
already interacts with the contract conditions.

## Rationale

Contracts provide a means for programs to state truths in ways that
programming systems may act upon.  It is anticipated that when contracts
are adopted in C++, existing programs will be augmented with them to
express such truths currently written as comments or implemented through
ordinary condition checks.

It is important that there be a way to add contracts such that programs
do not begin behaving in undesired ways when checking is disabled.
Otherwise adding contracts becomes a dangerous activity rather than a
means for enhancing program correctness - programs that currently check
for out-of-contract conditions and handle them may become erroneous by
the addition of a contract.

Furthermore, making unchecked contracts cause undefined behavior when
their predicate is false is confusingly different from the similar
feature provided by _cassert_.  In that case, when the `NDEBUG` macro
is defined, asserted conditions are ignored, not assumed to be true.

Similarly, contracts in the Ada programming language are controlled
by `pragma Assertion_Policy(_policy_);`, and the language defines
two policies, `Check` and `Ignore` (with the implementation permitted
to add additional ones).

## Example

Suppose we have the following function.

```
int foo(int x)
   // Return the result of dividing 100 by the specified 'x'.
   // The behavior is unspecified unless 'x' is positive.
{
    if (x <= 0) throw std::domain_error("foo - parameter not positive");
    return 100 / x;
}
```

With contracts available, we would like to add a precondition.

```
int foo(int x) [[ expects: x > 0 ]]
```

However, if the program is built with checks disabled, the programming
system is currently permitted to elide the range check within the function,
leading to formal undefined behavior if the function is called with argument 0.

## Wording

In `[dcl.attr.contract.check]/4`, modify as follows:

**_A translation may be performed with one of the following contract assumption
modes: off or on.  If no contract assumption mode is explicitly selected, the
default contract assumption mode is off._**  During constant expression evaluation
(7.7), only predicates of checked contracts are evaluated. In other contexts, it
is unspecified whether the predicate for a contract that is not checked under the
current build level is evaluated; if the predicate of such a contract would
evaluate to false **_and contract assumption mode is on_**, the behavior is undefined.

## Conclusion

Having contracts silently add new forms of undefined behavior can cause
existing programs to which contracts have been added to begin behaving
erroneously.  Such a feature should be enabled by specific request, not
by default.
