contract/doc/introduction.qbk
2019-06-05 15:56:56 -07:00

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]