What are contracts (as proposed for C++17)?

20,731

Solution 1

As far as I've read from this document: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4415.pdf

Contracts do what assert has been trying to do in a primitive way for years. They're both documentation and a run-time assert of how the caller should be expected to call the function and in what state can the caller expect the code to be after the function has returned. Those are usually known as pre-conditions and post-conditions, or invariants.

This helps clean up code on the implementation side, because with contracts we can assume that once the execution has gone inside your function, your arguments are in valid state (what you expect them to be).

The post-conditions part might change how you handle exceptions, because with contracts you will have to make sure that throwing an exception won't break your post-conditions. This usually means that your code has to be exception safe, though whether that means strong exception guarantee or basic guarantee depends on your conditions.

Example:

class Data;
class MyVector {
public:
    void MyVector::push_back(Elem e) [[ensures: data != nullptr]]
    {
        if(size >= capacity)
        {
            Data* p = data;
            data = nullptr; // Just for the sake of the example...
            data = new Data[capacity*2]; // Might throw an exception
            // Copy p into data and delete p
        }
        // Add the element to the end
    }
private:
     Data* data;
     // other data
};

In this example here, if new or Data's constructor throws an exception, your post-condition is violated. This means that you should change all such code to make sure your Contract is never violated!

Of course, just like assert, contracts might include a run-time overhead. The difference though is that since contracts can be put as part of the function's declaration, the compiler can do better optimizations, such as evaluating the conditions at the caller's site or even evaluate them at compile time. Section 1.5 of the document mentioned at the beginning of this post talks about the possibilities of turning off contracts depending on your build configuration, just like plain old asserts.

Solution 2

I started with the link from the original document OP provided. There are some answers, I suppose. I strongly recommend to start with that paper. Here is TL&DR version:

Contracts are not a general error reporting mechanism, nor are they substitute for testing frameworks. Rather, they offer a basic mitigation measure when a program goes wrong because of mismatch of expectations between parts of a program. Contracts are conceptually more like structured assert()integrated into the language, playing by the language semantics rules – therefore basis for principled program analysis and tooling.

About your questions:

  • It's structured assert(), so yes, it can be said that in some cases assert() must be replace with contract.
  • Let me use another quote here:

...the expression of a contract must logically be part of the declaration of the operation.

and example:

T& operator[](size_t i) [[expects: i < size()]];

In my opinion, this is just nice and readable.

  • In some cases contracts can replace exceptions:

However, it is a critical design criteria that contracts be usable in embedded systems or other resource-constrained systems that cannot afford exceptions.

In pre-condition contracts exceptions still can be used, as further behavior after pre-condition contract failure is not guaranteed.

  • Overhead can be reduced by turning contracts checking on/off in for cases: use all, use non, pre-condition only, post-condition only. Turned on contracts will definitely add some overhead, as any type of checks.

Some use cases (as I can suppose while i am not even close to developing a contracts design)

  1. Contracts - in case of usual assert() as contracts are more readable and can be optimized at compilation time.
  2. Asserts - in unit tests, testing frameworks etc.
  3. Exceptions - can be used with pre-conditioned contracts as mentioned in article:

The pre-condition of an operation is evaluated before any other statement in the function’s body. If the result is true, then normal control of execution continues to the first statement in the body of the function. Otherwise, further execution is not guaranteed: either the program aborts, or throws an exception, or if it is allowed to continue then the behavior is undefined.

There are also some other suggestions about contracts implementation, so our investigation is just premature.

Solution 3

It is not easy to answer your questions other that with: It depends. This is because it is not yet clear what contracts are going to be exactly. There are several proposals and ideas floating around right now:

  • n4378 Lakos et al. basically proposes to standardize a sophisticated assert toolkit. Contracts are checked inside of a functions implementation, 3 different assert levels are provided to control the amount of runtime checks and the handling of assert violations can be customized.

  • n4415 dos Reis et al. and n4435 Brown are fairly similar and propose a attribute based syntax to define pre and post conditions in the functions interfaces. They do not go into details on how much control they give over run-time checks and the behavior on violations.

There have been less recent papers on this topic, too. There are many details which are not yet decided, and this feature touches many different areas (e.g. modules, optimization, building/linking) over some of which the standard has little control.

Your question on exceptions is particularly difficult, because the interactions between contract violation handling and exceptions is unclear (e.g. could a contract violation handler throw (useful in test frameworks)? what if the function is noexcept(true)?).

Share:
20,731
coincoin
Author by

coincoin

\_o&lt; ^^^^ this is a duck. Unfamous answers where I have spent some time: Operator overloading for built in types in C++ to access elements in a 2D array How to detect and fix dead pixels in images using OpenCV? How to randomly generate a narrow path? OpenMP on super computer OpenMP for matrix multiplication How to create in ascii square, triangle, rectangle or circle with C++ and save it to portable bitmap file?

Updated on August 18, 2021

Comments

  • coincoin
    coincoin almost 3 years

    I read about contracts in Thoughts about C++17 by B. Stroustrup and assisted a small presentation talking about them but I am not sure I have understood them really.

    So I have some interrogations and if it is possible to illustrate them with some examples :

    • Are contracts just a better replacement of the classic assert(), and should they be used together? What contracts really are put in simple terms for a software dev?

    • Would contracts have an impact on how we handle exceptions? If yes, how should we use exceptions and contracts?

    • Would using contracts imply an overhead at execution time? Will we be allowed to deactivate them on release code?

    From the proposal N4415:

    A pre-condition contract of the indexing operator of a Vector class could be written:
    T& operator[](size_t i) [[expects: i < size()]];

    Similarly, a post-condition contract on a constructor of an ArrayView class could be expressed as: ArrayView(const vector<T>& v) [[ensures: data() == v.data()]];

    Thanks to @Keith Thompson comment:

    Contracts didn't make it into C++20. A new study group, SG21, has been created.

  • coincoin
    coincoin almost 9 years
    Thank you for your answer. So you say that depending on your context using assertion and exception can still be needed ? Is it possible to provide some examples on when using assertion, exception, or contracts seem more legit than the other ?
  • coincoin
    coincoin almost 9 years
    Thanks for the answer. So if I follow using assertions should be deprecated and we should use contracts instead. Could you provide an example on your "post condition might change exceptions" part ?
  • KABoissonneault
    KABoissonneault almost 9 years
    @coincoin You will definitely still want to use assert to evaluate post-conditions of functions that don't use Contracts (ex: this should never return null, but just in case...). Exceptions are in my opinion a system that's completely orthogonal to Contracts/asserts; exceptions should not be used for contract violation, but for exceptional situations, like a socket error or file handling error. Therefore they should still be used, but in my opinion not for pre-condition violation!
  • KABoissonneault
    KABoissonneault almost 9 years
    @coincoin Edited to include an example
  • Pavel Oganesyan
    Pavel Oganesyan almost 9 years
    @coincoin Agree with KABoissonneault about using exceptions for "out of code" problems, also some use cases added to answer.
  • Pavel Oganesyan
    Pavel Oganesyan almost 9 years
    @coincoin Assertions will not be deprecated as contracts are not fitting in testing frameworks,
  • Bakuriu
    Bakuriu almost 9 years
    AFAIK pre- and post- conditions have nothing to do with invariants. An invariant is a property that is preserved during all iterations of a loop. You may apply this definition to the call to a function: an invariant for a function f is a property preserved by the call to f. However this is not the same as pre- and post- conditions.
  • KABoissonneault
    KABoissonneault almost 9 years
    @Bakuriu Wikipedia documents Invariant and Loop invariant as two different things. While the article on Invariant makes no mention of pre- or post-conditions, it mentions invariants as being logical assertions. Of course, wikipedia is not the one authoritative knowledge base for computer science terms, but I assume that there are actually two different concepts known as invariants, the one I mentioned being only one of them
  • coincoin
    coincoin almost 9 years
    Thank you. So I guess we will have to wait some time in order to clarify some points.
  • Fabio Fracassi
    Fabio Fracassi almost 9 years
    Yes, or start getting involved and shape it.
  • Rakete1111
    Rakete1111 over 5 years
    Note that in C++20 contracts if you throw an exception than any post condition is not checked. It's only when you return normally, i.e. using a return statement;.
  • Anonymous
    Anonymous over 2 years
    Does anyone knows a valid piece of code with contracts which can be compiled, e.g., with g++? As far as I see the contract feature is not listed for C++20 nor for C++23: en.cppreference.com/w/cpp/compiler_support/23 ?