80 lines
6.4 KiB
Plaintext
80 lines
6.4 KiB
Plaintext
|
|
[/ Copyright (C) 2008-2018 Lorenzo Caminiti]
|
|
[/ Distributed under the Boost Software License, Version 1.0 (see accompanying]
|
|
[/ file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).]
|
|
[/ See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html]
|
|
|
|
[section Introduction]
|
|
|
|
Contract programming allows to specify preconditions, postconditions, and class invariants that are automatically checked when functions are executed at run-time.
|
|
These conditions assert program specifications within the source code itself allowing to find bugs more quickly during testing, making the code self-documenting, and increasing overall software quality (see __Contract_Programming_Overview__).
|
|
|
|
For example, consider the following function `inc` that increments its argument `x` by `1` and let's write its contract using code comments (see [@../../example/features/introduction_comments.cpp =introduction_comments.cpp=]):
|
|
|
|
[import ../example/features/introduction_comments.cpp]
|
|
[introduction_comments]
|
|
|
|
The precondition states that at function entry the argument `x` must be strictly smaller than the maximum allowable value of its type (so it can be incremented by `1` without overflowing).
|
|
The postcondition states that at function exit the argument `x` must be incremented by `1` with respect to the /old value/ that `x` had before executing the function (indicated here by [^['oldof]]`(x)`).
|
|
Note that postconditions shall be checked only when the execution of the function body does not throw an exception.
|
|
|
|
Now let's program this function and its contract using this library (see [@../../example/features/introduction.cpp =introduction.cpp=] and __Non_Member_Functions__):
|
|
|
|
[import ../example/features/introduction.cpp]
|
|
[introduction]
|
|
|
|
When the above function `inc` is called, this library will:
|
|
|
|
* First, execute the functor passed to `.precondition(...)` that asserts `inc` precondition.
|
|
* Then, execute `inc` body (i.e., all the code that follows the `boost::contract::check c = ...` declaration).
|
|
* Last, execute the functor passed to `.postcondition(...)` that asserts `inc` postcondition (unless `inc` body threw an exception).
|
|
|
|
For example, if there is a bug in the code calling `inc` so that the function is called with `x` equal to `std::numeric_limits<int>::max()` then the program will terminate with an error message similar to the following (and it will be evident that the bug is in the calling code):
|
|
|
|
[pre
|
|
precondition assertion "x < std::numeric_limits<int>::max()" failed: file "introduction.cpp", line 17
|
|
]
|
|
|
|
Instead, if there is a bug in the implementation of `inc` so that `x` is not incremented by `1` after the execution of the function body then the program will terminate with an error message similar to the following (and it will be evident that the bug is in `inc` body):
|
|
[footnote
|
|
In this example the function body is composed of a single trivial instruction `++x` so it easy to check by visual inspection that it does not contain any bug and it will always increment `x` by `1` thus the function postcondition will never fail.
|
|
In real production code, function bodies are rarely this simple and can hide bugs which make checking postconditions useful.
|
|
]
|
|
|
|
[pre
|
|
postcondition assertion "x == *old_x + 1" failed: file "introduction.cpp", line 20
|
|
]
|
|
|
|
By default, when an assertion fails this library prints an error message such the ones above to the standard error `std::cerr` and terminates the program calling `std::terminate` (this behaviour can be customized to take any user-specified action including throwing exceptions, see __Throw_on_Failures__).
|
|
Note that the error messages printed by this library contain all the information necessary to easily and uniquely identify the point in the code at which contract assertions fail.
|
|
[footnote
|
|
*Rationale:*
|
|
The assertion failure message printed by this library follows a format similar to the message printed by Clang when the C-style `assert` macro fails.
|
|
]
|
|
|
|
[note
|
|
C++11 lambda functions are necessary to use this library without manually writing a significant amount of boiler-plate code to program functors that assert the contracts (see __No_Lambda_Functions__).
|
|
That said, this library implementation does not use C++11 features and should work on most modern C++ compilers (see __Getting_Started__).
|
|
]
|
|
|
|
In addition to contracts for non-member functions as shown the in the example above, this library allows to program contracts for constructors, destructors, and member functions.
|
|
These can check class invariants and can also /subcontract/ inheriting and extending contracts from base classes (see [@../../example/features/introduction_public.cpp =introduction_public.cpp=] and __Public_Function_Overrides__):
|
|
[footnote
|
|
The `pushable` base class is used in this example just to show subcontracting, it is somewhat arbitrary and it will likely not appear in real production code.
|
|
]
|
|
|
|
[import ../example/features/introduction_public.cpp]
|
|
[introduction_public]
|
|
|
|
[heading Language Support]
|
|
|
|
The authors of this library advocate for contracts to be added to the core language.
|
|
Adding contract programming to the C++ standard has a number of advantages over any library implementation (shorter and more concise syntax to program contracts, specify contracts in declarations instead of definitions, enforce contract constant-correctness, expected faster compile- and run-time, vendors could develop static analysis tools to recognize and check contracts statically when possible, compiler optimizations could be improved based on contract conditions, etc.).
|
|
|
|
The __P0380__ proposal supports basic contract programming, it was accepted and it will be included in C++20.
|
|
This is undoubtedly a step in the right direction, but unfortunately __P0380__ only supports pre- and postconditions while missing important features such as class invariants and old values in postconditions, not to mention the lack of more advanced features like subcontracting (more complete proposals like __N1962__ were rejected by the C++ standard committee).
|
|
All contracting programming features are instead supported by this library (see __Feature_Summary__ for a detailed comparison between the features supported by this library and the ones listed in different contract programming proposals, see __Bibliography__ for a list of references considered during the design and implementation of this library, including the vast majority of contract programming proposals submitted to the C++ standard committee).
|
|
|
|
[endsect]
|
|
|