diff --git a/README.md b/README.md index 81b21ad..8677f34 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Boost.Contract ============== Contract programming for C++. -All contract programming features are supported: subcontracting, class invariants (also static and volatile), postconditions (with old and return values), preconditions, customizable actions on assertion failure (terminate, throw, etc.), optional compilation and checking of assertions, disable assertions while already checking other assertions (to avoid infinite recursion), etc. +All contract programming features are supported: Subcontracting, class invariants (also static and volatile), postconditions (with old and return values), preconditions, customizable actions on assertion failure (terminate, throw, etc.), optional compilation and checking of assertions, disable assertions while already checking other assertions (to avoid infinite recursion), etc. ### License diff --git a/TODO.txt b/TODO.txt index 3f093ec..34ed141 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,4 +1,7 @@ +* Do not align any of the comments in the docs examples +* Do not use complex ``formatted-text`` in the docs examples + * Proof read docs * Make sure build/, example/, and test/ all compile even if include/ is removed after symlink are created to //boost/... * Recompile all examples/tests with all compilers, boost_contract_no, link, boost_contract_header_only, etc. (after fully integrated w/ Boost build system) diff --git a/doc/advanced.qbk b/doc/advanced.qbk index 394cf85..034eed8 100644 --- a/doc/advanced.qbk +++ b/doc/advanced.qbk @@ -10,7 +10,7 @@ This section is a guide to advanced usages of this library. [section Pure Virtual Public Functions] -In C++, pure virtual functions are allowed to have a /default implementation/ as long as such implementation is programmed out-of-line so defined outside the class declaring the pure virtual function `virtual ... = 0;`. +In C++, pure virtual functions are allowed to have a [@http://en.cppreference.com/w/cpp/language/abstract_class default implementation] as long as such implementation is programmed out-of-line so defined outside the class declaring the pure virtual function `virtual ... = 0;`. Contracts for pure virtual public functions are programmed using the [funcref boost::contract::public_function] function like for (non-pure) virtual public functions (all consideration made in __Virtual_Public_Functions__ apply). However, contracts have to be programmed out-of-line, in the default implementation of the pure virtual function. @@ -22,25 +22,51 @@ For example (see [@../../example/features/pure_virtual_public.cpp =pure_virtual_ [pure_virtual_public_base_impl] This library will never actually execute the pure virtual function body while it is calling the pure virtual function default implementation to check contracts for subcontracting. -Therefore, programmers can safely `assert(false)` at the beginning of the body if they intend for that body to never be executed (or they can program a working body in case they need to use C++ pure virtual function default implementation as usual with C++). +Therefore, programmers can safely `assert(false)` at the beginning of the body if they intend for that body to never be executed (or they can program a working body in case they need to use pure virtual function default implementations as usual in C++). -[heading Subcontracting Preconditions Always True/False] +[heading Subcontracting Preconditions Always True or False] As seen in __Public_Function_Overrides__, preconditions of overriding public functions are checked in __OR__ with preconditions of overridden virtual public functions. -Therefore, if a virtual public function in a base class specifies no precondition then preconditions specified by all its overriding functions in derived classes will have no effect (because when checked in __OR__ with the overridden function from the base class that has no preconditions, they will always pass). -This correctly reflects the fact that the overridden function in the base class can be called from any context (because it has no precondition) and so must all its overriding functions in all derived classes in accordance to the __substitution_principle__. -This is equivalent to declare the virtual public function in a base class with a single precondition `BOOST_CONTRACT_ASSERT(true)` that will always pass: +Therefore, if a virtual public function in a base class specifies no precondition then preconditions specified by all its overriding functions in derived classes will have no effect (because when checked in __OR__ with the overridden function from the base class that has no preconditions, they will always pass): +[footnote +This consequence of the __substitution_principle__ ["that if any function in an inheritance hierarchy has no preconditions, then preconditions on functions overriding it have no useful effect] is also explicitly mentioned in the contract documentation of the D Programming Language (see __Bright04__). +] + + class u { // Some base class. + public: + virtual void f(boost::contract::virtual_* v = 0) { + boost::contract::check c = boost::contract::public_function(v, this) + // No preconditions, same as `ASSERT(true)`. + ... + ; + + ... + } - // In a virtual public function of a base class. - boost::contract::check c = boost::contract::public_function(v, this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(true); // Prevent preconditions of overrides. - }) ... - ; + }; + +This correctly reflects the fact that the overridden function in the base class can be called from any context (because it has no precondition) and so must all its overriding functions in all derived classes in accordance to the __substitution_principle__. +In other words, the code above has the effect as declaring the virtual public function in the base class with a single precondition `BOOST_CONTRACT_ASSERT(true)` that will always trivially pass: + + class u { // Some base class. + public: + virtual void f(boost::contract::virtual_* v = 0) { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([] { + BOOST_CONTRACT_ASSERT(true); // Same as no preconditions. + }) + ... + ; + + ... + } + + ... + }; On the flip side, programmers might sometimes consider to declare a pure virtual public function in a base class with a single precondition `BOOST_CONTRACT_ASSERT(false)` that will always fail. -This indicates that the pure virtual public function can never be called unless it is redefined by a derived class (which is actually the case with C++ pure virtual functions) and also that the base class designers have intentionally left it up to derived classes to specify preconditions for the pure virtual function in question. +This indicates that the pure virtual public function can never be called unless it is redefined by a derived class (which is already the case with C++ pure virtual functions) and also that the base class designers have intentionally left it up to derived classes to specify preconditions for the pure virtual function in question. This technique might make sense only for preconditions of pure virtual public functions (otherwise `BOOST_CONTRACT_ASSERT(false)` will prevent calling virtual public functions in concrete bases). For example (see [@../../example/features/named_override.cpp =named_override.cpp=]): @@ -52,12 +78,12 @@ In general, the base class interface should still contain all functions (eventua [endsect] -[section Optional Return Value] +[section Optional Return Values] It is possible to use `boost::optional` to handle return values when programmers cannot construct the result variable at its point of declaration before the contract (e.g., because an appropriate constructor for the return type is not available at that point, or just because it would be too expensive to execute an extra initialization of the return value at run-time). [footnote *Rationale:* -`boost::optional` is used instead of `std::optional` because `std::optional` is not part of C++ standards prior to C++17. +This library uses `boost::optional` instead of `std::optional` because `std::optional` is not available before C++17. ] For example (see [@../../example/features/optional_result.cpp =optional_result.cpp=]): @@ -65,22 +91,22 @@ For example (see [@../../example/features/optional_result.cpp =optional_result.c [optional_result] In this example the return type is a reference so it does not have default constructor that can be used to initialize `result` when it is declared before the contract declaration. -In addition, `Index` needs to be validated to be smaller than `size()` by the precondition before it can be used to retrieve the reference to be assigned to `result` so `vect[Index]` cannot be used to initialize `result` when it is declared before the contract declaration. -Therefore, `boost::optional` is used to defer `result` proper initialization until the execution of the function body after the contract declaration when `Index` has been validated by the precondition and `vect[Index]` can be safely evaluated to initialize `result`. +In addition, `Index` needs to be validated to be smaller than `size()` by the precondition before it can be used to retrieve the reference to assign to `result` so `vect[Index]` cannot be used to initialize `result` when it is declared before the contract declaration. +Therefore, `boost::optional` is used to defer `result` proper initialization until the execution of the function body, after the contract declaration, where `Index` has been validated by the precondition and `vect[Index]` can be safely evaluated to initialize `result`. -As seen in __Return_Value__, it is the responsibility of the programmers to ensure that `result` is always set to the return value (when the function exits without trowing an exception). +As seen in __Return_Values__, it is the responsibility of the programmers to ensure that `result` is always set to the return value (when the function exits without trowing an exception). This also ensures that `result` is always set before the postconditions are checked so programmers can always dereference `result` in postconditions to access the return value (using `operator*` and `operator->` as usual with `boost::optional`, and without having to explicitly check if `result` is an empty `boost::optional` object or not). -This can be easily done by making sure that /all/ return statements in the function are of the form: +This can be done ensuring that /all/ return statements in the function are of the form: - boost::optional<...> result; + boost::optional result; ... - return *(result = ...); // Assign `result` at each return. + return *(result = return_expr); // Assign `result` at each return. [heading Optional Results in Virtual Public Functions] Similarly, `boost::optional` can be used to handle the return value passed to contracts of virtual public functions (pure or not) and of public function overrides. As seen in __Pure_Virtual_Public_Functions__, __Virtual_Public_Functions__, and __Public_Function_Overrides__, in these cases the return value `result` must be passed as a parameter to [funcref boost::contract::public_function] right after the parameter `v` of type [classref boost::contract::virtual_]`*`. -Then the functor passed to `.postcondition(...)` takes one single parameter of type `boost::optional<`[^['result-type]]` const&> const&`. +Then the functor passed to `.postcondition(...)` takes one single parameter of type `boost::optional<`[^['return-type]]` const&> const&`. For example (see [@../../example/features/optional_result_virtual.cpp =optional_result_virtual.cpp=]): [import ../example/features/optional_result_virtual.cpp] @@ -90,7 +116,7 @@ The inner `const&` in the postcondition functor parameter type `boost::optional< [footnote *Rationale:* This library requires the postcondition functor parameter to be of type `boost::optional<... const&>` so the return value does not have to be copied (because of `&`) while postconditions are still not allowed to change its value (because of `const`, see __Constant_Correctness__). -In addition, programmers are encouraged to declare the postcondition functor to take its argument also as a constant reference `boost::optional<... const&> const&` to avoid possibly expensive copies of the `boost::optional` type. +In addition, programmers are encouraged to declare the postcondition functor to take its argument also as a constant reference `boost::optional<... const&> const&` to avoid possibly expensive copies of the `boost::optional` type itself. ] [endsect] @@ -99,19 +125,18 @@ In addition, programmers are encouraged to declare the postcondition functor to Private and protected functions do not check class invariants (because they are not part of the public class interface) and they do not subcontract (because they are not accessible at the calling site where the __substitution_principle__ applies, see __Function_Calls__). However, programmers may still want to specify preconditions and postconditions for private and protected functions when they want to check correctness of their implementation and usage from within the class, base classes, and friend classes or functions. -When programmers decide to specify contracts for private and protected functions, they shall use [funcref boost::contract::function] (like for non-member functions). +When programmers decide to specify contracts for private and protected functions, they shall use [funcref boost::contract::function] (because, like for non-member functions, this does not check class invariants and does not subcontract). For example (see [@../../example/features/private_protected.cpp =private_protected.cpp=]): [import ../example/features/private_protected.cpp] [private_protected] Considerations made in __Non_Member_Functions__ apply to private and protected functions as well. - See __Constructors__ and __Destructors__ on how to program contracts for private and protected constructors and destructors instead. [heading Virtual Private and Protected Functions] -When private and protected functions are virtual they should still declare the extra virtual parameter of type [classref boost::contract::virtual_]`*` with default value `0` (see __Virtual_Public_Functions__) even if that parameter does not have to be passed to [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::function] takes no argument (so the extra virtual parameter will remain unused and it does not need a name). +When private and protected functions are virtual they should still declare the extra virtual parameter of type [classref boost::contract::virtual_]`*` with default value `0` (see __Virtual_Public_Functions__) even if that parameter does not have to be passed to [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::function] takes no such an argument (so the extra virtual parameter will remain unused and it does not need a name). [footnote Technically, the extra virtual parameter can still be passed to [macroref BOOST_CONTRACT_OLDOF] but that is not necessary and it has no effect so it is not done in this documentation. ] @@ -149,16 +174,16 @@ For example (see [@../../example/features/friend.cpp =friend.cpp=]): [import ../example/features/friend.cpp] [friend_byte] -[friend_bytes] +[friend_buffer] However, in some cases a friend function might take an object as parameter and it can be logically considered an extension of that object's public interface (essentially at the same level as the object's public functions). -In these cases, programmers might chose to program the friend function contracts using [funcref boost::contract::public_function] (instead of [funcref boost::contract::function]) so to also check the class invariants of the object passed as parameter (and not just the pre- and postconditions of the friend function). +In these cases, programmers might chose to program the friend function contracts using [funcref boost::contract::public_function] (instead of [funcref boost::contract::function]) so to also check the class invariants of the object passed as parameter (and not just pre- and postconditions). For example (see [@../../example/features/friend_invariant.cpp =friend_invariant.cpp=]): [footnote *Rationale:* Contract programming proposals for C++ like __N1962__ do not provide a mechanism for friend functions to check class invariants of objects passed as parameters. In other words, these proposals do not enable contracts to recognize that in C++ some friend functions logically act as if they were part of the public interface of the objects they take as parameters. -This is actually reasonable for proposals that add contracts to the core language because friend functions are not always meant to extend an object public interface and C++ does not provide a mechanism to programmatically specify when they do and when they do not. +This is reasonable for proposals that add contracts to the core language because friend functions are not always meant to extend an object public interface and C++ does not provide a mechanism to programmatically specify when they do and when they do not. However, this library adds the flexibility to let programmers manually specify when friend functions should also check class invariants of the objects they take as parameters (using [funcref boost::contract::public_function]) and when they should not (using [funcref boost::contract::function] instead). ] @@ -189,7 +214,7 @@ For example: ... // Function body. } -Changing the order of the [classref boost::contract::check] declarations above, programmers can chose the order for checking class invariants among the different objects passed to the friend function and also whether to check these invariants before or after preconditions, postconditions, and exception guarantees at function entry and exit respectively (see __Non_Member_Functions__ and __Public_Functions__ for information on how the RAII objects returned by [funcref boost::contract::function] and [funcref boost::contract::public_function] check contract conditions). +Changing the order of the [classref boost::contract::check] declarations above, programmers can chose the order for checking class invariants among the different objects passed to the friend function and also whether to check these invariants before or after preconditions, postconditions, and exception guarantees of the friend function (see __Non_Member_Functions__ and __Public_Functions__ for information on how the RAII objects returned by [funcref boost::contract::function] and [funcref boost::contract::public_function] check contract conditions). The example above is programmed to check `class1` invariants before `class2` invariants (but the order could have been inverted if programmers so chose). [note @@ -201,8 +226,9 @@ In the example above, preconditions are intentionally programmed to be checked b [section Function Overloads] -As seen in __Public_Function_Overrides__, [funcref boost::contract::public_function] takes a pointer to the enclosing function as a parameter when used in public function overrides. -When names of public function overrides are overloaded, the function pointer cannot be automatically deduced by the compiler so programmers have to use `static_cast` to resolve ambiguities (as usual with pointers to overloaded functions in C++). +No special attention is required when using this library with overloaded functions or constructors. +The only exception is for the function pointer passed to [funcref boost::contract::public_function] from public function overrides (see __Public_Function_Overrides__). +When the name of public function override are also overloaded, the related function pointer cannot be automatically deduced by the compiler so programmers have to use `static_cast` to resolve ambiguities (as usual with pointers to overloaded functions in C++). [footnote *Rationale:* In order to avoid copies, this library takes all function arguments and the return value passed to [funcref boost::contract::public_function] as references when used within public function overrides. @@ -215,8 +241,8 @@ For example, note how `static_cast` is used in the following calls to [funcref b [import ../example/features/overload.cpp] [overload] -Overloaded functions have the same function name so the same [^override_['function-name]] type can be reused as template parameter for all [funcref boost::contract::public_function] calls. -Therefore, [macroref BOOST_CONTRACT_OVERRIDE] only needs to be invoked once for any given function name even when that function name is overloaded. +Overloaded functions have the same function name so the same [^override_['function-name]] type can be reused as template parameter for all [funcref boost::contract::public_function] calls in a given class. +Therefore, [macroref BOOST_CONTRACT_OVERRIDE] only needs to be invoked once for a function name in a given class, even when that function name is overloaded. [endsect] @@ -224,7 +250,7 @@ Therefore, [macroref BOOST_CONTRACT_OVERRIDE] only needs to be invoked once for While contracts are usually most useful to program specifications of functions and class interfaces, this library also allows to check contract conditions for implementation code (lambda functions, loops, code blocks, etc.). -Lambda functions are not member functions, they are not part of class public interfaces so they do not check class invariants or participate int subcontracting. +Lambda functions are not member functions, they are not part of class public interfaces so they do not check class invariants and they do not subcontract. They can use [funcref boost::contract::function] to specify preconditions, postconditions, and exception guarantees (considerations made in __Non_Member_Functions__ apply). For example (see [@../../example/features/lambda.cpp =lambda.cpp=]): @@ -247,7 +273,7 @@ Finally, at the moment this library does not support contracts for functions and [footnote *Rationale:* In general, it might be useful to specify contracts for `constexpr` functions and literal classes. -However, the implementation of this library cannot support contracts for these functions and classes because C++ does not currently allow `constexpr` functions to do the following: +However, the implementation of this library cannot support contracts for `constexpr` functions and classes because C++ does not currently allow `constexpr` functions to do the following: Declare local variables of (literal) types with non-trivial `constexpr` destructors (this RAII technique is used by this library to check invariants, postconditions, and exceptions guarantees at exit); Call other `constexpr` functions using try-catch statements (used by this library to report contract assertion failures and catch any other exception that might be thrown when evaluating the asserted conditions); Use lambda functions (used by this library for convenience to program functors that that check preconditions, postconditions, and exception guarantees). @@ -258,25 +284,52 @@ Also note that even if supported, contracts for `constexpr` functions probably w [section Implementation Checks] -This library provides a mechanism to check assertions within implementation code outside of preconditions, postconditions, exceptions guarantees, and class invariants. -These implementation checks can be programmed using [macroref BOOST_CONTRACT_ASSERT] in a nullary functor that is directly assigned to [classref boost::contract::check] at the place within the code where the checks have to be executed (so without using [funcref boost::contract::function], [funcref boost::contract::public_function], etc.). +This library provides a mechanism to check assertions within implementation code a part from preconditions, postconditions, exceptions guarantees, and class invariants. +Implementation checks are programmed using a nullary functor that is directly assigned to a [classref boost::contract::check] object declaration right at the place within the code where the checks need to be performed (without calling [funcref boost::contract::function], [funcref boost::contract::public_function], etc. in this case). For example (see [@ ../../example/features/check.cpp =check.cpp=]): [import ../example/features/check.cpp] -[check_class] +[check] -Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove run- and compile-time overhead of implementation checks when [macroref BOOST_CONTRACT_NO_CHECKS] is defined. -For example (see [@ ../../example/features/check.cpp =check.cpp=]): +The implementation check functor should capture all the variables that it needs to assert the implementation checks. +These variables can be captured by value when the overhead of copying such variables is acceptable. +In any case, implementation checks should not modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__). +Any code can be programmed in the implementation check functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex checks that might be buggy and also slow to check at run-time). +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): + + BOOST_CONTRACT_ASSERT(bool_cond) + // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + +This library will automatically call the failure handler [funcref boost::contract::check_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if calling the implementation check functor throws any exception. +By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). + +Similarly to the C-style `assert` macro that is disable when `NDEBUG` is defined, implementation checks are disabled when [macroref BOOST_CONTRACT_NO_CHECKS] is defined. +That will skip all implementation checks at run-time but it will not eliminate some of the overhead of executing and compiling the related [classref boost::contract::check] declarations. +Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove run- and compile-time overhead of implementation checks when [macroref BOOST_CONTRACT_NO_CHECKS] is defined (this is not a variadic macro): + + BOOST_CONTRACT_CHECK(bool_cond) + // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_CHECK((bool_cond)) // ...use extra parenthesis (not a variadic macro). + +For example (see [@ ../../example/features/check_macro.cpp =check_macro.cpp=]): + +[import ../example/features/check_macro.cpp] [check_macro] -(See __Disable_Contract_Checking__ and __Disable_Contract_Compilation__ for macros to completely remove run- and compile-time overhead of preconditions, postconditions, exception guarantees, and class invariants.) +The [macroref BOOST_CONTRACT_CHECK] macro is similar to the C-style assert macro as it accepts a boolean condition (instead of a nullary functor like [classref boost::contract::check] does). +[footnote +Of course, nothing prevents programmers from calling functors to specify boolean conditions when if-guards and other statements are required to assert the implementation checks. +For example, programmers can use C++11 lambda functions to define and call such functors in place where the implementation checks are specified `BOOST_CONTRACT_CHECK([...] -> bool { ... } ())`. +] +Using [macroref BOOST_CONTRACT_CHECK] is essentially equivalent to using the C-style `assert` macro a part from the following: -These implementation checks are essentially equivalent to using the C-style `assert` macro a part from the following: - -* A failure of the implementation checks will call [funcref boost::contract::check_failure] (see [funcref boost::contract::set_check_failure] and [funcref boost::contract::get_check_failure]). -* Implementation checks are automatically disabled when other contract conditions specified using this libraries are already being checked (to avoid infinite recursion, see [macroref BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION]). * Implementation checks are disabled defining [macroref BOOST_CONTRACT_NO_CHECKS] (instead of `NDEBUG` for disabling `assert`). +* If the asserted boolean condition is either false or it throws an exception then this library will call [funcref boost::contract::check_failure] (instead `assert` calls `std::abort` if the asserted condition is false and unwinds the stack if evaluating the condition throws an exception). +* Implementation checks are automatically disabled when other contract conditions specified using this library are already being checked (to avoid infinite recursion, see [macroref BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION]). + +(See __Disable_Contract_Checking__ and __Disable_Contract_Compilation__ for macros to completely remove run- and compile-time overhead also for preconditions, postconditions, exception guarantees, and class invariants.) [endsect] @@ -289,7 +342,8 @@ This might work well in most cases, however in general old values should be copi Specifically, there could be cases in which it makes sense to evaluate the expressions passed to [macroref BOOST_CONTRACT_OLDOF] only assuming that the assertions programmed in the class invariants and preconditions are first checked to be true. This library allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and then to assign them later to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] in a nullary functor [^['d]]`()` passed to `.old(`[^['d]]`)`. -The functor [^['d]]`()` is called by this library before the function body is executed but only after class invariants and preconditions are checked: +The functor [^['d]]`()` is called by this library before the function body is executed but only after class invariants and preconditions are checked. +Old value assignments via `.old(...)` must appear after preconditions but before postconditions and exception guarantees wen these are all present (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__): [footnote *Rationale:* Functors for preconditions, old value assignments, postconditions, and exception guarantees are all optional but when specified, they must be specified in that order. @@ -299,9 +353,9 @@ Other contract programming frameworks allow to mix this order, that could have b ] boost::contract::old_ptr<...> old_``[^['name]]``; // Default constructor (i.e., null pointer). - ... + ... // More old values here if needed. boost::contract::guard c = boost::contract::function() // Same for all other contracts. - ... + .precondition(...) // Preconditions shall not use old values. .old([&] { // Capture by reference... old_``[^['name]]`` = BOOST_CONTRACT_OLDOF(``[^['expression]]``); // ...but modify only old values. ... @@ -326,7 +380,7 @@ The functor passed to `.old(...)` should capture all variables it needs to evalu In general, these variables should be captured by reference and not by value (because old values need to make copies of the values the captured variables will have just before executing the function body, and not copy the values these variables had when the functor passed to `.old(...)` was first declared). In any case, the functor passed to `.old(...)` should modify only old values and not the values of other captured variables (see __Constant_Correctness__). -This library will automatically call the failure handler [funcref boost::contract::old_failure] if calling the functor specified via `.old(...)` throws an exception (by default, this handler prints an error message to `std::cerr` and terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). +This library will automatically call the failure handler [funcref boost::contract::old_failure] if calling the functor specified via `.old(...)` throws an exception (by default, this handler prints an error message to `std::cerr` and terminates the program calling `std::terminate`, but see __Throw_on_Failures__ to throw exceptions, exit the program with an error code, etc.). [note If old value pointers are initialized at the point of their construction instead of using `.old(...)` then an exception thrown by the old value expression passed to [macroref BOOST_CONTRACT_OLDOF], or more in general any exception thrown by the old value pointer initialization, will result in that exception being thrown up the stack by the enclosing function. @@ -404,7 +458,7 @@ Therefore, programmers should always make sure to either declare invariant funct [endsect] -[section Throw on Failure (and `noexcept`)] +[section Throw on Failures (and `noexcept`)] If a conditions checked using [macroref BOOST_CONTRACT_ASSERT] is evaluated to be `false` or more in general if any of the specified contract code throws an exception ([macroref BOOST_CONTRACT_ASSERT] simply expands to code that throws a [classref boost::contract::assertion_failure] exception, see __No_Macros__), this library will call an appropriate /contract failure handler/ function as follow: diff --git a/doc/bibliography.qbk b/doc/bibliography.qbk index a20d36b..e62ab7a 100644 --- a/doc/bibliography.qbk +++ b/doc/bibliography.qbk @@ -10,7 +10,7 @@ This section lists all references consulted while designing and developing this [#Andrzej13_anchor] [Andrzej13] A. Krzemienski. [@https://akrzemi1.wordpress.com/2013/01/04/preconditions-part-i/ /Andrzej's C++ blog: Preconditions/]. 2013. -[#Bright04_anchor] [Bright04] W. Bright. [@http://www.digitalmars.com/d/2.0/dbc.html /Contract Programming for the D Programming Language/]. 2004. +[#Bright04_anchor] [Bright04] W. Bright. [@https://dlang.org/spec/contracts.html /Contract Programming for the D Programming Language/]. 2004. [#Bright04b_anchor] [Bright04b] W. Bright. [@http://www.digitalmars.com/ctg/contract.html /Contract Programming for the Digital Mars C++ Compiler/]. 2004. diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk index 82ed84e..debce13 100644 --- a/doc/contract_programming_overview.qbk +++ b/doc/contract_programming_overview.qbk @@ -15,7 +15,7 @@ Readers that already have a basic understanding of contract programming can skip [note The objective of this library is not to convince programmers to use contract programming. It is assumed that programmes understand the benefits and trade-offs associated with contract programming and they have already decided to use this methodology in their code. -Then, this library aims to be the best and more complete contract programming library for C++ (that does not use preprocessors and other tools external to the C++ preprocessor and language itself). +Then, this library aims to be the best and more complete contract programming library for C++ (without using preprocessors and other tools external to the C++ preprocessor and language itself). ] [section Assertions] @@ -24,22 +24,23 @@ Contract programming is characterized by the following assertion mechanisms: * /Preconditions/: These are logical conditions that programmers expect to be true when a function is called (e.g., to check constraints on function arguments). Operations that logically have no preconditions (i.e., that are always well-defined for the entire domain of their inputs) are often referred to as having a /wide contract/. -This is in contrast to operations that have preconditions which are often referred to as having a /narrow contract/ (note that operations with truly narrow contracts should not even throw exceptions). +This is in contrast to operations that have preconditions which are often referred to as having a /narrow contract/ (note that operations with truly narrow contracts are expected to also never throw exceptions). [footnote The nomenclature of wide and narrow contracts has gained some popularity in recent years in the C++ community (appearing in a number of more recent proposals to add contract programming to the C++ standard, see __Bibliography__). -This nomenclature is perfectly reasonable but it is not often used in this document because the authors generally prefer to explicit mention "this operation has no preconditions..." or "this operation has preconditions...". +This nomenclature is perfectly reasonable but it is not often used in this document just because the authors generally prefer to explicitly mention "this operation has no preconditions..." or "this operation has preconditions...". ] * /Postconditions/: These are logical conditions that programmers expect to be true when a function exits without throwing an exception (e.g., to check the result and any side effect that a function might have). -Postconditions can access the function return value (for non-void functions) and /old values/ that expressions had before the function body was executed. +Postconditions can access the function return value (for non-void functions) and also /old values/ (which are the values that expressions had before the function body was executed). * /Exception guarantees/: These are logical conditions that programmers except to be true when a function exits throwing an exception. -Exceptions specifications can access old values (but not the function return value). +Exception guarantees can access old values (but not the function return value). [footnote *Rationale:* Contract assertions for exception guarantees were first introduced by this library (even if exception safety guarantees have long been part of C++ STL documentation). Contract assertions for exception safety guarantees are not part of __N1962__ or other references listed in the __Bibliography__. ] -* /Class invariants/: These are logical conditions that programmers expect to be true after a constructor exits without throwing an exception, before and after the execution of every non-static public non-static function (even if they throw exceptions), before the destructor is executed and if the destructor throws an exception (i.e., class invariants define valid states for all objects of a given class). -It is possible to specify a different set of class invariants for volatile public functions, namely /volatile class invariants/. +* /Class invariants/: These are logical conditions that programmers expect to be true after a constructor exits without throwing an exception, before and after the execution of every non-static public function (even if they throw exceptions), before the destructor is executed (and also after the destructor is executed but only when the destructor throws an exception). +Class invariants define valid states for all objects of a given class. +It is possible to specify a different set of class invariants for volatile public functions, namely volatile class invariants. It is also possible to specify /static class invariants/ which are excepted to be true before and after the execution of any constructor, destructor (even if it does not throw an exception), and public function (even if static). [footnote *Rationale:* @@ -48,7 +49,7 @@ Static and volatile class invariants are not part of __N1962__ or other referenc ] * /Subcontracting/: This indicates that preconditions cannot be strengthen, while postconditions and class invariants cannot be weaken when a public function in a derived class overrides public functions in one or more of its base classes (this is formally defined according to the __substitution_principle__). -Class invariants can also be used to specify /basic/ exception safety guarantees for an object (because they are checked at exit of public functions even when those throw an exception), while contract assertions for exception guarantees can be used to specify /strong/ exception safety guarantees for given operations on the same object. +Class invariants can also be used to specify /basic/ exception safety guarantees for an object (because they are checked at exit of public functions even when those throw exceptions), while contract assertions for exception guarantees can be used to specify /strong/ exception safety guarantees for given operations on the same object. It is also a common requirement for contract programming to automatically disable contract checking while already checking assertions from another contract (in order to avoid infinite recursion while checking contract assertions). @@ -62,7 +63,7 @@ This library will automatically protect such a global variable from race conditi ] In general, it is recommended to specify different contract conditions using separate assertion statements and not to group them together into a single condition using logical operators (`&&`, `||`, etc.). -This is because when contract conditions are programmed together in a single assertion using logical operators, it is not be clear which condition actually failed in case the entire assertion fails at run-time. +This is because when contract conditions are programmed together in a single assertion using logical operators, it might not be clear which condition actually failed in case the entire assertion fails at run-time. [heading C-Style Assertions] @@ -70,11 +71,11 @@ A limited form of contract programming is the use of the C-style `assert` macro. Using `assert` is common practice for many programmers but it suffers of the following limitations: * `assert` does not distinguish between preconditions and postconditions. -In well-tested production code, postconditions can usually be disabled trusting the correctness of the implementation while preconditions might still need to remain enabled because of possible changes in the calling code (e.g., postconditions of a given library could be disabled after testing while its preconditions can be kept enabled given the library cannot predict the evolution of user code that will be calling it). +In well-tested production code, postconditions can usually be disabled trusting the correctness of the implementation while preconditions might still need to remain enabled because of possible changes in the calling code (e.g., postconditions of a given library could be disabled after testing while its preconditions can be kept enabled given the library cannot predict changes in the user code that will be calling the library). Using `assert` it is not possible to selectively disable only postconditions and all assertions must be disabled at once. * `assert` requires to manually program extra code to check class invariants (extra member functions, try blocks, etc.). * `assert` does not support subcontracting. -* `assert` calls are usually scattered within function implementations thus the asserted conditions are not immediately visible in their entirety by programmers (as they are instead when the assertions appear in the function declaration or at least at the very top of function definition). +* `assert` calls are usually scattered within function implementations thus the asserted conditions are not immediately visible in their entirety by programmers (as they are instead when the assertions appear in the function declaration or at least at the very top of the function definition). Contract programming does not suffers of these limitations. @@ -87,7 +88,7 @@ Contract programming does not suffers of these limitations. The main use of contract programming is to improve software quality. __Meyer97__ discusses how contract programming can be used as the basic tool to write ["correct] software. __Stroustrup94__ discusses the key importance of class invariants plus advantages and disadvantages of preconditions and postconditions. -The following is a short summary of the benefits associated with contract programming inspired mainly by __N1613__: +The following is a short summary of benefits associated with contract programming inspired mainly by __N1613__: * Preconditions and postconditions: Using function preconditions and postconditions, programmers can give a precise semantic description of what a function requires at its entry and what it ensures at its exit (if it does not throw an exception). @@ -96,9 +97,9 @@ This mechanism is powerful enough to enable programmers to express many correctn * Class invariants: Using class invariants, programmers can describe what to expect from a class and the logic dependencies between the class members. It is the job of the constructor to ensure that the class invariants are satisfied when the object is first created. -Then the implementation of the member functions can be largely simplified as they can be written knowing that the class invariants are satisfied because Contract Programing checks them before and after the execution of every public function. +Then the implementation of the member functions can be largely simplified as they can be written knowing that the class invariants are satisfied because contract programming checks them before and after the execution of every public function. Finally, the destructor makes sure that the class invariants held for the entire life of the object checking the class invariants one last time before the object is destructed. -Class invariants can also be used as a criterion for good abstraction: If it is not possible to specify an invariant, it might be an indication that the design abstraction maybe be poor and it should not have been made into a class. +Class invariants can also be used as a criteria for good abstractions: If it is not possible to specify an invariant, it might be an indication that the design abstraction maybe be poor and it should not have been made into a class (maybe a namespace would have sufficed instead). * Self-documenting code: Contracts are part of the source code, they are checked at run-time so they are always up-to-date with the code itself. Therefore program specifications, as documented by the contracts, can be trusted to always be up-to-date with the implementation. @@ -107,12 +108,12 @@ Contract programming can provide a powerful debugging facility because, if contr Note that a precondition failure points to a bug in the function caller, a postcondition failure points instead to a bug in the function implementation. [footnote Of course, if contracts are ill-written then contract programming is of little use. -However, it is less likely to have a bug in both the function body and the contract than in the function body only. +However, it is less likely to have a bug in both the function body and the contract than in the function body alone. For example, consider the validation of a result in postconditions. Validating the return value might seem redundant, but in this case we actually want that redundancy. When programmers write a function, there is a certain probability that they make a mistake in implementing the function body. When programmers specify the result of the function in the postconditions, there is also a certain probability that they make a mistake in writing the contract. -However, the probability that programmers make a mistake twice (in both the body /and/ the contract) is in general lower than the probability that the mistake is made just once (in either the body or the contract). +However, the probability that programmers make a mistake twice (in both the body /and/ the contract) is in general lower than the probability that the mistake is made only once (in either the body /or/ the contract). ] * Easier testing: Contract programming facilitates testing because a contract naturally specifies what a test should check. @@ -123,8 +124,8 @@ Moreover, contracts can make code reviews easier by clarifying some of the seman * Formalized inheritance: Contract programming formalizes the virtual function overriding mechanism using subcontracting as justified by the __substitution_principle__. This keeps the base class programmers in control as overriding functions always have to fully satisfy the contracts of their base classes. -* Replace Defensive Programming: -Contract programming assertions can replace [@http://en.wikipedia.org/wiki/Defensive_programming Defensive Programming] checks localizing these checks within the contract and making the code more readable. +* Replace defensive programming: +Contract programming assertions can replace [@http://en.wikipedia.org/wiki/Defensive_programming defensive programming] checks localizing these checks within the contracts and making the code more readable. Of course, not all formal contract specifications can be asserted in C++. For example, in C++ is it not possible to assert the validity of an iterator range in the general case because the only way to check if two iterators form a valid range is to keep incrementing the first iterator until we reach the second iterator. @@ -139,7 +140,7 @@ While performance trade-offs should be carefully considered depending on the spe The run-time performances are negatively impacted by contract programming mainly because of extra time require to: * Check the asserted conditions. -* Copy old values when these are used in postconditions and exception guarantees. +* Copy old values when these are used in postconditions or exception guarantees. * Call additional functors that check preconditions, postconditions, exception guarantees, class invariants, etc. (especially for subcontracting). [note @@ -154,11 +155,11 @@ Programmers will have to decide based on the performance trade-offs required by * Always write contracts to clarify the semantics of the design embedding the specifications directly in the code and making the code self-documenting. * Check preconditions, postconditions, class invariants, and maybe even exception guarantees during initial testing. -* Only check preconditions (and maybe class invariants, but not postconditions and exception guarantees) during release testing and for the final release. +* Check only preconditions (and maybe class invariants, but not postconditions and exception guarantees) during release testing and for the final release. This approach is usually reasonable because in well-tested production code, validating the function body implementation using postconditions is rarely needed since the function has shown itself to be ["correct] during testing. On the other hand, checking function arguments using preconditions is always needed because of changes that can be made to the calling code (without having to necessarily re-test and re-release the called code). -Furthermore, postconditions and also exception guarantees, with related old value copies, are often computationally more expensive to check than preconditions and even class invariants. +Furthermore, postconditions and also exception guarantees, with related old value copies, are often computationally more expensive to check than preconditions and class invariants. [endsect] @@ -175,10 +176,10 @@ A call to a non-member function with a contract executes the following steps (se [heading Private and Protected Functions] -In contract programming, private and protected functions do not have to satisfy the class invariants because these functions are part of the class implementation and not of the class public interface. +Private and protected functions do not have to satisfy class invariants because these functions are part of the class implementation and not of the class public interface. Furthermore, the __substitution_principle__ does not apply to private and protected functions because these functions are not accessible to the user at the calling site where the __substitution_principle__ applies. -Therefore, calls to private and protected functions with contracts execute the same steps as the ones indicated above for non-member functions (checking only preconditions and postconditions, but without checking class invariants and without subcontracting). +Therefore, calls to private and protected functions with contracts execute the same steps as the ones indicated above for non-member functions (checking only preconditions and postconditions, without checking class invariants and subcontracting). [endsect] @@ -186,7 +187,7 @@ Therefore, calls to private and protected functions with contracts execute the s [heading Overriding Public Functions] -Let's consider a public function in a derived class that overrides public virtual functions declared in a number of its public base classes (because of C++ multiple inheritance, the function could override from more than one base class). +Let's consider a public function in a derived class that overrides public virtual functions declared its public base classes (because of C++ multiple inheritance, the function could override from more than one of its base classes). We refer to the function in the derived class as the /overriding function/, and to the set of base classes containing all the /overridden functions/ as /overridden bases/. When subcontracting, overridden functions are searched (at compile-time) deeply in the public branches of the inheritance tree (i.e., not just the derived class's direct public parents are inspected, but also all its public grandparents, etc.). @@ -202,11 +203,12 @@ A call to the overriding public function with a contract executes the following # If the body did not throw an exception, check postconditions of overridden public functions from all overridden bases in __AND__ with each other, __AND__ then check the overriding function postconditions in the derived class. # Else, check exception guarantees of overridden public functions from all overridden bases in __AND__ with each other, __AND__ then check the overriding function exception guarantees in the derived class. -Volatile public functions check static class invariants __AND__ /volatile/ class invariants instead. +Volatile public functions check static class invariants __AND__ volatile class invariants instead. Preconditions and postconditions of volatile public functions and volatile class invariants access the object as `volatile`. Class invariants are checked before preconditions and postconditions so programming precondition and postcondition assertions can be simplified assuming that class invariants are satisfied already (e.g., if class invariants assert that a pointer cannot be null then preconditions and postconditions can safety dereference that pointer without additional checking). -Similarly, subcontracting checks contracts of public base classes before checking the derived class contracts so programming derived class contract assertions can be simplified by assuming that public base class contracts are satisfied already. +Similarly, static class invariants are checked before non-static class invariants so programming non-static class invariant (volatile and non) can be simplified assuming that static class invariants are satisfied already. +Furthermore, subcontracting checks contracts of public base classes before checking the derived class contracts so programming derived class contract assertions can be simplified by assuming that public base class contracts are satisfied already. [note [#and_anchor] [#or_anchor] @@ -227,7 +229,7 @@ A call to a non-static public function with a contract (that does not override f # If the body did not throw an exception, check function postconditions (but none of the postconditions from functions in base classes). # Else, check function exception guarantees (but none of the exception guarantees from functions in base classes). -Volatile public functions check static class invariants __AND__ /volatile/ class invariants instead. +Volatile public functions check static class invariants __AND__ volatile class invariants instead. Preconditions and postconditions of volatile functions and volatile class invariants access the object as `volatile`. Class invariants are checked because this function is part of the class public interface. @@ -295,7 +297,7 @@ As indicated in step 4.b. above, C++ object destruction mechanism will automatic [note Given that C++ allows destructors to throw, this library handles the case when the destructor body throws an exception as indicated above. -However, in order to comply with STL exception safety guarantees and good C++ programming practices, programmers should implement destructor bodies to rarely, if ever, throw exceptions (in fact destructors are declared `noexcept` by default in C++11). +However, in order to comply with STL exception safety guarantees and good C++ programming practices, programmers should implement destructor bodies to rarely, if ever, throw exceptions (in fact destructors are implicitly declared `noexcept` in C++11). ] [endsect] @@ -303,47 +305,46 @@ However, in order to comply with STL exception safety guarantees and good C++ pr [section Constant-Correctness] Contracts should not be allowed to modify the program state because they are only responsible to check (and not to change) the program state in order to verify its compliance with the specifications. -Therefore, contracts should only have access to the object, function arguments, function return value, old values, and all other program variables in `const` context (via `const&`, `const* const`, `const volatile`, etc.). +Therefore, contracts should only access objects, function arguments, function return values, old values, and all other program variables in `const` context (via `const&`, `const* const`, `const volatile`, etc.). Whenever possible (e.g., class invariants and postcondition old values), this library automatically enforces this constant-correctness constraint at compile-time using `const`. However, this library cannot automatically enforce this constraint in all cases (for preconditions and postconditions of mutable member functions, for global variables, etc.). -See __No_Lambda_Functions__ for ways of using this library that always and automatically enforce the constant-correctness constraint at compile-time (but these methods require a significant amount of boiler-plate code to be programmed manually so they are not recommended in general). +See __No_Lambda_Functions__ for ways of using this library that enforces the constant-correctness constraint at compile-time (but at the cost of significant boiler-plate code to be programmed manually so not recommended in general). [note In general, it is the responsibility of the programmers to code assertions that only check, and do not change, program variables. [footnote -Note that also when using C-style `assert` it is the responsibility of the programmers to code assertions that only check and do not change program variables. +Note that this is true when using C-style `assert` as well. ] ] [endsect] -[section Specification vs. Implementation] +[section Specifications vs. Implementation] -Contracts are part of the program specification and not of its implementation. +Contracts are part of the program specifications and not of its implementation. Therefore, contracts should ideally be programmed within C++ declarations, and not within definitions. In general, this library cannot satisfy this requirement. -However, even when the contracts are programmed together with the body in the function definition, it is still very easy for users to identify and read just the contract portion of the function definition (because the contract code must always be programmed at the very top of the function definition). -See __Separate_Body_Implementation__ for ways of using this library to program contract specifications outside of the body implementation but at the cost of writing one extra function for any given function (for applications were this requirement is truly important). +However, even when contracts are programmed together with the body in the function definition, it is still fairly easy for users to identify and read just the contract portion of the function definition (because the contract code must always be programmed at the very top of the function definition). +See __Separate_Body_Implementation__ for ways of using this library to program contract specifications outside of the body implementation (but at the cost of writing one extra function for any given function, for applications where this requirement is truly important). Furthermore, contracts are most useful when they assert conditions only using public members (in most cases, the need for using non-public members to check contracts, especially in preconditions, indicates an error in the class design). For example, the caller of a public function cannot in general make sure that the function preconditions are satisfied if the precondition assertions use private members that are not callable by the caller (therefore, a failure in the preconditions will not necessarily indicate a bug in the caller given that the caller was made unable to fully check the preconditions in the first place). - However, given that C++ provides programmers ways around access level restrictions (`friend`, function pointers, etc.), this library leaves it up to the programmers to make sure that only public members are used in contract assertions (especially in preconditions). (__N1962__ follows the same approach not restricting contracts to only use public members, Eiffel instead generates a compile-time error if preconditions are asserted using non-public members.) [footnote *Rationale:* -If C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] had not been fixed, this library could have been implemented so to generate a compile-time error when precondition assertions use non-public members more similarly to Eiffel's implementation (but not necessary the best approach for C++). +If C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] had not been fixed, this library could have been implemented to generate a compile-time error when precondition assertions use non-public members more similarly to Eiffel's implementation (but not necessary the best approach for C++). ] [endsect] -[section On Contract Failure] +[section On Contract Failures] -If precondition, postcondition, exception guarantee, or class invariant assertions are either checked to be false or their evaluation throws an exception at run-time then this library will call specific /failure handler functions/. +If preconditions, postconditions, exception guarantees, or class invariants are either checked to be false or their evaluation throws an exception at run-time then this library will call specific /failure handler functions/. By default, these failure handler functions print a message to the standard error `std::cerr` (with detailed information about the failure) and then terminate the program calling `std::terminate`. -However, using [funcref boost::contract::set_precondition_failure], [funcref boost::contract::set_postcondition_failure], [funcref boost::contract::set_except_failure], [funcref boost::contract::set_invariant_failure], etc. programmers can define their own failure handler functions that can take any user-specified action (throw an exception, exit the program with an error code, etc., see __Throw_on_Failure__). +However, using [funcref boost::contract::set_precondition_failure], [funcref boost::contract::set_postcondition_failure], [funcref boost::contract::set_except_failure], [funcref boost::contract::set_invariant_failure], etc. programmers can define their own failure handler functions that can take any user-specified action (throw an exception, exit the program with an error code, etc., see __Throw_on_Failures__). [footnote *Rationale:* This customizable failure handling mechanism is similar to the one used by C++ `std::terminate` and also to the one proposed in __N1962__. @@ -351,8 +352,8 @@ This customizable failure handling mechanism is similar to the one used by C++ ` [note In C++ there are a number of issues with programming contract failure handlers that throw exceptions instead of terminating the program. -Specifically, destructors check class invariants so they will throw if programmers change class invariant failure handlers to throw instead of terminating the program, but in general destructors should not throw in C++ (to comply with STL exception safety, etc.). -Furthermore, programming an exception guarantee failure handler to throw will throw an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception guarantees to be checked in the first place), and this will force C++ to terminate the program anyway. +Specifically, destructors check class invariants so they will throw if programmers change class invariant failure handlers to throw instead of terminating the program, but in general destructors should not throw in C++ (to comply with STL exception safety, C++11 implicit `noexcept` declarations for destructors, etc.). +Furthermore, programming a failure handler that throws for exception guarantees will throw an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception guarantees to be checked in the first place), and this will force C++ to terminate the program anyway. ] Therefore, it is recommended to terminate the program at least for contract failures from destructors and exception guarantees (if not in all other cases of contract failures as it is done by default by this library). @@ -363,7 +364,7 @@ The contract failure handler functions programmed using this library have inform [section Feature Summary] The contract programming features supported by this library are largely based on __N1962__ and on the Eiffel programming language. -The following table compares contract programming features among this library, __N1962__ (unfortunately the C++ standard committee rejected this proposal commenting on a general lack of need for adding contract programming to C++ at the time, even if __N1962__ itself is sound), a more recent proposal __P0380__ (which unfortunately only supports preconditions and postconditions, but does not support class invariants, old values, and subcontracting), the Eiffel and D programming languages: +The following table compares contract programming features among this library, __N1962__ (unfortunately the C++ standard committee rejected this proposal commenting on a lack of interest in adding contract programming to C++ at that time, even if __N1962__ itself is sound), a more recent proposal __P0380__ (which has gain some traction within the C++ standard committee but unfortunately only supports preconditions and postconditions, while does not support class invariants, old values, and subcontracting), the Eiffel and D programming languages: [table [ @@ -382,71 +383,72 @@ The last three specifiers appear in user code so their names can be referred to [Keywords: `precondition`, `postcondition`, `oldof`, and `invariant`.] [Attributes: `[[expects]]` and `[[ensures]]`.] [Keywords: =require=, =require else=, =ensure=, =ensure then=, =old=, =result=, =do=, and =invariant=.] - [Keywords: =in=, =out=, =assert=, and =invariant=.] + [Keywords: =in=, =out=, =do=, =assert=, and =invariant=.] ][ - [['On contract failure]] + [['On contract failures]] [Print an error to `std::cerr` and call `std::terminate` (but can be customized to throw exceptions, exit with an error code, etc.).] [Call `std::terminate` (but can be customized to throw exceptions, exit with an error code, etc.).] [Call `std::abort` (but can be customized to throw exceptions, exit with an error code, etc.).] [Throw exceptions.] [Throw exceptions.] ][ - [['Result value in postconditions]] + [['Return values in postconditions]] [Yes, captured by or passed as a parameter to (for virtual functions) the postcondition functor.] [Yes, `postcondition(`[^['result-variable-name]]`)`.] [Yes, `[[ensures `[^['result-variable-name]]`: ...]]`.] [Yes, =result= keyword.] - [No.] + [Yes, `out(`[^['result-variable-name]]`)`.] ][ [['Old values in postconditions]] [ -Yes, [macroref BOOST_CONTRACT_OLD] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old(...)` is used as shown in __Old_Copies_at_Body__). +Yes, [macroref BOOST_CONTRACT_OLDOF] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old(...)` is used as shown in __Old_Copies_at_Body__). For templates, [classref boost::contract::old_ptr_if_copyable] skips old value copies for non-copyable types and [funcref boost::contract::condition_if] skips old value copies selectively based on old expression type requirements. ] [ -Yes, `oldof` keyword (copied after preconditions and before body). +Yes, `oldof` keyword (copied right after preconditions). (Never skipped, not even in templates for non-copyable types.) ] [No.] [ -Yes, =old= keyword (copied after preconditions and before body). +Yes, =old= keyword (copied right after preconditions). (Never skipped, but all types are copyable in Eiffel.) ] [No.] ][ [['Class invariants]] [ -Checked at constructor exit, at destructor entry and throw, and at public function entry, exit, and throw. +Yes, checked at constructor exit, at destructor entry and throw, and at public function entry, exit, and throw. Same for volatile class invariants. -Static class invariants checked at entry and exit of constructor, destructor, and any (also `static`) public function. +Static class invariants checked at entry, exit, and throw for constructors, destructors, and any (also `static`) public function. ] [ -Checked at constructor exit, at destructor entry and throw, and at public function entry, exit, and throw. +Yes, checked at constructor exit, at destructor entry and throw, and at public function entry, exit, and throw. (Volatile and static class invariants not supported.) ] [No.] [ -Checked at constructor exit, and around public functions. +Yes, checked at constructor exit, and around public functions. (Volatile and static class invariants do not apply to Eiffel.) ] [ -Checked at constructor exit, at destructor entry, and around public functions. +Yes, checked at constructor exit, at destructor entry, and around public functions. +However, invariants cannot call public functions (to avoid infinite recursion because D does not disable contracts while checking other contracts). (Volatile and static class invariants not supported, `volatile` was deprecated all together in D.) ] ][ [['Subcontracting]] [ -Yes, also supports subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used for declaring base classes, overriding and virtual public functions respectively). +Yes, also supports subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used for declaring base classes, overrides and virtual public functions respectively). ] [ -Yes, also supports subcontracting for multiple inheritance but only preconditions only in base classes. +Yes, also supports subcontracting for multiple inheritance, but preconditions cannot be subcontracted. [footnote *Rationale:* -The authors of __N1962__ decided to forbid derived classes from subcontracting preconditions because they found that such a feature was rarely, if evet, used (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). +The authors of __N1962__ decided to forbid derived classes from subcontracting preconditions because they found that such a feature was rarely, if ever, used (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). Still, it should be noted that even in __N1962__ if a derived class overrides two functions with preconditions coming from two different base classes via multiple inheritance, the overriding function contract will check preconditions from its two base class functions in __OR__ (so even in __N1962__ preconditions can indirectly subcontract when multiple inheritance is used). The authors of this library found that confusing about __N1962__. Furthermore, subcontracting preconditions is soundly defined by the __substitution_principle__ so this library allows to subcontract preconditions as Eiffel does (users can always avoid using this feature if they have no need for it). -(This is essentially the only feature for which this library deliberately differ from __N1962__.) +(This is essentially the only feature on which this library deliberately differ from __N1962__.) ] ] [No.] @@ -454,32 +456,32 @@ Furthermore, subcontracting preconditions is soundly defined by the __substituti [Yes.] ][ [['Contracts for pure virtual functions]] - [Yes (but they must be programmed in out-of-line functions as always in C++ with pure virtual function definitions).] + [Yes (programmed via out-of-line functions as always in C++ with pure virtual function definitions).] [Yes.] [No (because no subcontracting).] [Yes (contracts for abstract functions).] - [No (but planned).] + [No.] ][ [['Arbitrary code in contracts]] [Yes (but users are generally recommended to only program assertions using [macroref BOOST_CONTRACT_ASSERT] and if-guard statements within contracts to avoid introducing bugs and expensive code in contracts, and also to only use public functions to program preconditions).] - [No, assertions only.] - [No, assertions only. In addition only public members can be used in preconditions.] - [No, assertions only. In addition only public members can be used in preconditions.] + [No, assertions only (use of only public functions to program preconditions is recommended but not prescribed).] + [No, assertions only (in addition only public members can be used in preconditions).] + [No, assertions only (in addition only public members can be used in preconditions).] [Yes.] ][ [['Constant-correctness]] - [Enforced only for class invariants and old values (making also preconditions and postconditions constant-correct is possible but requires users to program a fare amount of boiler-plate code).] + [No, enforced only for class invariants and old values (making also preconditions and postconditions constant-correct is possible but requires users to program a fare amount of boiler-plate code).] [Yes.] [Yes.] [Yes.] - [No.] + [No, enforced only for class invariants.] ][ - [['Contracts in specifications or implementation]] - [Implementation (unless programmers manually write an extra function for any given function).] - [Specification (function declaration).] - [Specification (function declaration).] - [Specification.] - [Specification.] + [['Contracts in specifications]] + [No, in function definitions instead (unless programmers manually write an extra function for any given function).] + [Yes (in function declarations).] + [Yes (in function declarations).] + [Yes.] + [Yes.] ][ [['Function code ordering]] [Preconditions, postconditions, exception guarantees, body.] @@ -494,9 +496,10 @@ Yes, but use [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] to dis [footnote *Rationale:* Theoretically, it can be shown that an incorrect argument might be passed to the function body when assertion checking is disabled while checking preconditions (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). -Therefore, __N1962__ does not disable any assertion while checking preconditions. -However, that makes it possible to have infinite recursion while checking preconditions, plus Eiffel disables assertion checking also while checking preconditions. -Therefore, this library by default disables assertion checking also while checking preconditions, but it also provides the [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] configuration macro so users can change this behaviour if needed. +However, that possibility is limited to contract checking when an incorrect argument will simply fail the contract and call the related contract failure handler as expected anyway. +In any case, because of that __N1962__ does not disable any assertion while checking preconditions. +That makes it possible to have infinite recursion while checking preconditions so Eiffel disables assertion checking also while checking preconditions. +Therefore, this library by default disables assertion checking also while checking preconditions, but it also provides the [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] configuration macro so users can change this behaviour to match __N1962__ if needed. ] (In multi-threaded programs this introduces a global lock, see [macroref BOOST_CONTRACT_DISABLE_THREADS].) ] @@ -511,7 +514,7 @@ Disable nothing. [footnote *Rationale:* Older versions of this library defined a data member in the user class that was automatically used to disable checking of class invariants within nested member function calls (similarly to Eiffel). -This feature was also required by older revisions of __N1962__ but it is no longer required by __N1962__. +This feature was required by older revisions of __N1962__ but it is no longer required in __N1962__ (because it seems to be motivated purely by optimization reasons while similar performances can be achieved by disabling invariants for release builds). Furthermore, in multi-threaded programs this feature would introduce a lock that synchronizes all member functions calls for a given object. Therefore, this feature was removed in the current revision of this library. ] @@ -529,21 +532,25 @@ Therefore, this feature was removed in the current revision of this library. [Yes.] ][ [['Assertion levels]] - [Yes, predefined default, audit, and axiom plus programmers can define their own levels.] - [No (but a previous revision of this proposal considered adding assertion levels called "assertion ordering").] + [Yes, predefined default, audit, and axiom, in addition programmers can also define their own levels.] + [No (but a previous revision of this proposal considered adding assertion levels under the name of "assertion ordering").] [Yes, predefined default, audit, and axiom.] [No.] [No.] ] ] -The authors of this library also consulted the following references that implemented contract programming for C++ (but usually for only a limited set of features, or using preprocessing tools other than the C++ preprocessor and external to the language itself) or for languages other than C++ (see __Bibliography__ for a complete list of all the references consulted in the design and development of this library): +The authors of this library consulted the following references that implement contract programming for C++ (but usually for only a limited set of features, or using preprocessing tools other than the C++ preprocessor and external to the language itself) and for other languages (see __Bibliography__ for a complete list of all the references consulted during the design and development of this library): [table [ [Reference] [Language] [Notes] ] -[ [__Bright04b__] [C++] [ +[ [__Bright04b__] [Digital Mars C++] [ The Digital Mars C++ compiler extends C++ adding contract programming language support (among many other features). ] ] +[ [__Maley99__] [C++] [ +This supports contract programming including subcontracting but with limitations (e.g., programmers need to manually build an inheritance tree using artificial template parameters), it does not use macros but programmers are required to write by hand a significant amount of boiler-plate code. +(The authors have found this work very inspiring when developing initial revisions of this library especially for its attempt to support subcontracting.) +] ] [ [__Lindrud04__] [C++] [ This supports class invariants and old values but it does not support subcontracting (contracts are specified within definitions instead of declarations and assertions are not constant-correct). ] ] @@ -552,15 +559,11 @@ Interestingly, these contract macros automatically generate Doxygen documentatio [footnote *Rationale:* Older versions of this library also automatically generated Doxygen documentation from contract definition macros. -This functionality was abandoned for a number of reasons: this library no longer uses macros to program contracts; even before that, the implementation of this library macros became too complex and the Doxygen preprocessor was no longer able to expand them; the Doxygen documentation was just a repeat of the contract code (so programmers could directly look at contracts in the source code); Doxygen might not necessarily be the documentation tool used by all C++ programmers. +This functionality was abandoned for a number of reasons: This library no longer uses macros to program contracts; even before that, the implementation of this library macros became too complex and the Doxygen preprocessor was no longer able to expand them; the Doxygen documentation was just a repeat of the contract code (so programmers could directly look at contracts in the source code); Doxygen might not necessarily be the documentation tool used by all C++ programmers. ] but old values, class invariants, and subcontracting are not supported (plus contracts are specified within definitions instead of declarations and assertions are not constant-correct). ] ] -[ [__Maley99__] [C++] [ -This supports contract programming including subcontracting but with limitations (e.g., programmers need to manually build an inheritance tree using artificial template parameters), it does not use macros but programmers are required to write by hand a significant amount of boiler-plate code. -(The authors have found this work very inspiring when developing initial revisions of this library especially for its attempt to support subcontracting.) -] ] -[ [__Nana__] [C++] [ +[ [__Nana__] [GCC C++] [ This uses macros but it only works on GCC (and maybe Clang, but it does not work on MSVC, etc.). It does not support subcontracting. It requires extra care to program postconditions for functions with multiple return statements. @@ -590,13 +593,12 @@ This is an Ada-like programming language with support for contract programming. ] ] ] -To the best knowledge of the authors, this the only library that fully supports all contract programming features for C++. -Generally speaking: +To the best knowledge of the authors, this the only library that fully supports all contract programming features for C++ (without using preprocessing tools external to the language itself): * Implementing preconditions and postconditions in C++ is not difficult (e.g., using some kind of RAII object). * Implementing postcondition old values is also not too difficult usually requiring programmers to copy old values into local variables, but it is already somewhat more difficult to ensure such copies are not performed when postconditions are disabled. [footnote -For example, the following emulation of old values based on __P0380__ never disables old value copies plus requires boiler-plate code to make sure postconditions are correctly checked in a `scope_exit` RAII object after all other local objects have been destroyed (because some of these destructors contribute to establishing the postconditions) and only if the function did not throw an exception: +For example, the following pseudocode attempts to emulate old values using __P0380__ (`scope_exit` here is an RAII object that executes the nullary functor passed to its constructor when it is destroyed): `` void fswap(file& x, file& y) [[expects: x.closed()]] @@ -627,12 +629,13 @@ For example, the following emulation of old values based on __P0380__ never disa t.mv(y); } `` -Here `scope_exit` is an RAII object that executes the nullary functor passed to its constructor when it is destroyed. +This requires boiler-plate code to make sure postconditions are correctly checked only if the function did not throw an exception and in a `scope_exit` RAII object after all other local objects have been destroyed (because some of these destructors contribute to establishing the postconditions). +Still, it never disables old value copies (not even if postconditions are disabled in release builds). ] * Implementing class invariants is more involved (especially if done automatically, without requiring programmers to manually invoke extra functions to check the invariants). [footnote -For example, the following possible emulation of class invariants based on __P0380__ requires boiler-plate code to manually invoke the function that checks the invariants (note that invariants are checked at public function exit regardless of exceptions being thrown while postconditions are not): +For example, the following pseudocode attempts to emulation of class invariants using __P0380__: `` template class vector { @@ -664,7 +667,9 @@ For example, the following possible emulation of class invariants based on __P03 ... }; `` +This requires boiler-plate code to manually invoke the function that checks the invariants (note that invariants are checked at public function exit regardless of exceptions being thrown while postconditions are not). In case the destructor can throw (e.g., it is declared `noexcept(false)`), the destructor also requires a `try-catch` statement similar to the one programmed for `push_back` to check class invariants at destructor exit when it throws exceptions. +Still, an outstanding issue remains to avoid infinite recursion if also `empty` and `size` are public functions programmed to check class invariants (because __P0380__ does not automatically disable assertions while checking other assertions). ] All references reviewed by the authors seem to not consider static and volatile functions not supporting static and volatile invariants respectively. diff --git a/doc/examples.qbk b/doc/examples.qbk index 4c08137..8c7e35a 100644 --- a/doc/examples.qbk +++ b/doc/examples.qbk @@ -115,7 +115,7 @@ On compilers that support C++17 `if constexpr`, the following example using this [mitchell02_simple_queue] [endsect] -[section \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] +[section \[Mitchell02\] Customer Manager: Contracts instead of defensive programming] [import ../example/mitchell02/customer_manager.cpp] [mitchell02_customer_manager] [endsect] diff --git a/doc/extras.qbk b/doc/extras.qbk index 6c6761d..ef829b7 100644 --- a/doc/extras.qbk +++ b/doc/extras.qbk @@ -425,7 +425,7 @@ Therefore, in most cases the compile-time overhead of contracts should not repre [section Separate Body Implementation] -Contracts are part of the program specification and not of its implementation (see __Specification_vs_Implementation__). +Contracts are part of the program specifications and not of its implementation (see __Specifications_vs_Implementation__). However, this library uses function definitions to program contracts so contract code appears together with the function implementation code. This is not ideal (even if contracts programmed using this library will always appear at the very beginning of the function definition so programmers will easily be able to distinguish contract code from the rest of the function implementation code and this might not be real problem in practise). @@ -435,7 +435,41 @@ If contracts are programmed in function definitions that are compiled in the obj In any case, when it is truly important to separate contracts from function implementation code, function implementations can be programmed in extra /body functions/ (e.g., named `..._body`) that are compiled in object files. Function definitions that remain in header files instead will contain just contract code followed by calls the extra body functions. -This technique allows to keep the contract code in header files while separating the implementation code to object files but at the cost of manually programming an extra function declaration for the body function (and with the limitation that constructor member initialization lists must be programmed in header files because that is where constructors need to be defined to list the constructor contract code). +This technique allows to keep the contract code in header files while separating the implementation code to object files. +However, it adds the overhead of manually programming an extra function declaration for the body function (and with the limitation that constructor member initialization lists must be programmed in header files because that is where constructors need to be defined to list the constructor contract code). +[footnote +When used as default parameter values, lambda functions allow to program code in function declarations but they cannot be effectively used to program contracts because the C++11 standard does not allow them to capture any variable. +For example, the following code does not compile: +`` +// Specifications (in declaration). +int inc(int& x, + // Error: Lambdas in default parameters cannot capture `this`, `x`, or any other variable. + std::function pre = [&] { + BOOST_CONTRACT_ASSERT(x < std::numeric_limits::max()); + }, + std::function const&)> post + = [&] (int const& result, boost::contract::old_ptr const& old_x) + { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); + BOOST_CONTRACT_ASSERT(result == *old_x); + } +); + +// Implementation (in definition). +int inc(int& x, std::function pre, std::function< + void (int const&, boost::contract::old_ptr const&)> post) { + int result; + boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::check c = boost::contract::function() + .precondition(pre) + .postcondition(std::bind(post, std::cref(result), std::cref(old_x))) + ; + + return result = x++; // Function body. +} +`` +In any case, even if the above code would compile, it requires boiler-plate code to bind return and old values. +] For example, the following header file only contains function declarations, contract code, and constructor member initializations, but it does not contain the code implementing the function bodies (see [@../../example/features/separate_body.hpp =separate_body.hpp=]): @@ -469,7 +503,7 @@ This has some advantages: * Contract functions (i.e., the `..._precondition`, `..._old`, and `..._postcondition` functions in the example below) can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see __Constant_Correctness__). [footnote If C++ allowed lambda functions to capture variables by constant reference (for example using the syntax `[const&] { ... }` and `[const& `[^['variable-name]]`] { ... }`, see [@https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/0UKQw9eo3N0]) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. -Note that C++11 lambdas allow to capture variables by value (`[=] { ... }` and `[`[^['variable-name]]`] { ... }`), these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions and exception guarantees using this library (because those require capturing by reference, see __Postconditions__ and __Exception_Guarantees__), plus they introduce a copy of the captured value that might be too expensive in general and therefore not suitable for preconditions either. +Note that C++11 lambdas allow to capture variables by value (using `[=] { ... }` and `[`[^['variable-name]]`] { ... }`), these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions and exception guarantees using this library (because those require capturing by reference, see __Postconditions__ and __Exception_Guarantees__), plus they introduce a copy of the captured value that might be too expensive in general and therefore not suitable for preconditions either. ] * Code of the contract functions is separated from function body implementations (see __Separate_Body_Implementation__). [footnote @@ -549,7 +583,7 @@ No need to also support C++11 `__func__` because this will always expand to the } In fact, this library considers any exception thrown from within preconditions, postconditions, exception guarantees, and class invariants as a contract failure and reports it calling the related contract failure handler ([funcref boost::contract::precondition_failure], etc.). -If there is a need for it, programmers can always program contract assertions that throw specific user-defined exceptions as follow (see __Throw_on_Failure__): +If there is a need for it, programmers can always program contract assertions that throw specific user-defined exceptions as follow (see __Throw_on_Failures__): if(!``[^['condition]]``) throw ``[^['exception-object]]``; diff --git a/doc/full_table_of_contents.qbk b/doc/full_table_of_contents.qbk index 8a66399..14ad1b7 100644 --- a/doc/full_table_of_contents.qbk +++ b/doc/full_table_of_contents.qbk @@ -21,14 +21,14 @@ __Contract_Programming_Overview__ __Constructor_Calls__ __Destructor_Calls__ __Constant_Correctness__ - __Specification_vs_Implementation__ - __On_Contract_Failure__ + __Specifications_vs_Implementation__ + __On_Contract_Failures__ __Feature_Summary__ __Tutorial__ __Non_Member_Functions__ __Preconditions__ __Postconditions__ - __Return_Value__ + __Return_Values__ __Old_Values__ __Exception_Guarantees__ __Class_Invariants__ @@ -41,7 +41,7 @@ __Tutorial__ __Static_Public_Functions__ __Advanced__ __Pure_Virtual_Public_Functions__ - __Optional_Return_Value__ + __Optional_Return_Values__ __Private_and_Protected_Functions__ __Friend_Functions__ __Function_Overloads__ @@ -50,7 +50,7 @@ __Advanced__ __Old_Copies_at_Body__ __Named_Overrides__ __Access_Specifiers__ - __Throw_on_Failure_and_noexcept__ + __Throw_on_Failures_and_noexcept__ __Extras__ __Old_Value_Requirements_Templates__ __Assertion_Requirements_Templates__ diff --git a/doc/getting_started.qbk b/doc/getting_started.qbk index 15b5a85..ce75c40 100644 --- a/doc/getting_started.qbk +++ b/doc/getting_started.qbk @@ -10,30 +10,30 @@ This section presents preliminary information to start using this library. [section This Documentation] -Programmers should be able to start using this library after reading __Introduction__, __Getting_Started__, and __Tutorial__. +Programmers should be able to start using this library after reading the __Introduction__, __Getting_Started__, and __Tutorial__. Other sections of this documentation (e.g., __Advanced__ and __Extras__) can be consulted at a later point to gain a more in-depth knowledge of the library. __Contract_Programming_Overview__ can be skipped by programmers that are already familiar with the contract programming methodology. -Some of the source code of the examples linked by this documentation contain special code comments of the form `//[...` and `//]`. -These mark sections of the code that are automatically extracted from the source and presented as part of this documentation. +Some of the source code listed in this documentation contains special code comments of the form `//[...` and `//]`. +These mark sections of the code that are automatically extracted from the source code and presented as part of this documentation. [footnote *Rationale:* This allows to make sure that most of the example code presented in this documentation is always up-to-date, builds and runs with the latest implementation of the library. ] -Also the purpose of all examples in this documentation is to illustrate how to use this library and not to represent real product code. +It should be noted that the purpose of all examples of this documentation is to illustrate how to use this library and not to represent real product code. Some footnotes are marked by the word "*Rationale*". -These explain reasons behind decisions made during the design and implementation of this library. +These explain some of the decisions made during the design and implementation of this library. [endsect] [section Compilers and Platforms] -In general, this library requires a C++ compiler with support for SFINAE and other template meta-programming techniques part of the C++03 standard. +In general, this library requires a C++ compiler with a sound support for SFINAE and other template meta-programming techniques as part of the C++03 standard. It is possible to use this library without C++11 lambda functions but a large amount of boiler-plate code is required to manually program separate functor to specify preconditions, postconditions, etc. (so using this library without C++11 lambda functions is possible but not recommended, see __No_Lambda_Functions__). It is also possible to use this library without variadic macros by manually programming a small amount of boiler-plate code (but most if not all modern C++ compilers support variadic macros even before C++99 and C++11 so this should never be needed in practice, see __No_Macros__). -Some parts of this documentation use an operator [^['type-of](...)] to indicate an operator logically equivalent to C++11 `decltype(...)`. +Some parts of this documentation use the syntax [^['type-of](...)] to indicate an operator logically equivalent to C++11 `decltype(...)`. However, this library implementation does not actually use type deduction in these cases (because the library already knows the types in question) so support for C++11 `decltype` and other type-of implementations are not actually required by this library (that is why [^['type-of]] and not the real `decltype` operator is used in this documentation). This library has been developed and tested using: @@ -42,12 +42,14 @@ This library has been developed and tested using: * GCC version 5.4.0 on Cygwin (with C++11 features enabled =-std=c++11=). * Clang version 3.8.1 on Cygwin (with C++11 features enabled =-std=c++11=). +For information on other compilers and platforms see the library [@http://www.boost.org/development/tests/master/developer/contract.html regression tests]. + [warning It is strongly recommended to compile and use this library as a shared library (a.k.a., Dynamically Linked Library or DLL) by defining the `BOOST_ALL_DYN_LINK` macro (or at least [macroref BOOST_CONTRACT_DYN_LINK]) when building Boost. -It is possible to compile and use this library as a static library (by defining the [macroref BOOST_CONTRACT_STATIC_LINK] macro) or as a header-only library (by leaving both [macroref BOOST_CONTRACT_DYN_LINK] and [macroref BOOST_CONTRACT_STATIC_LINK] undefined as by default). +It is possible to compile and use this library as a static library (by defining the [macroref BOOST_CONTRACT_STATIC_LINK] macro) or as a header-only library (by leaving both [macroref BOOST_CONTRACT_DYN_LINK] and [macroref BOOST_CONTRACT_STATIC_LINK] undefined, as by default). However, this library is not guaranteed to always work correctly in these cases. -Specifically, this library might not correctly disable contracts while checking other contracts and call the correct user-defined contract failure handlers unless it is compiled as a shared library when it is used in different program units (different programs, different shared libraries in the same program, etc.). +Specifically, this library might not correctly disable contracts while checking other contracts and call the correct user-defined contract failure handlers unless it is compiled as a shared library when it is used across different program units (different programs, different shared libraries in the same program, etc.). ] [endsect] @@ -58,15 +60,17 @@ All headers required by this library can be included at once by: #include -Or by the following when using the macro interface (see __Disable_Contract_Compilation__): +Or, by the following when using the library macro interface (see __Disable_Contract_Compilation__): #include -Alternatively, all =boost/contract/*.hpp= headers are independent from one another and they can be selectively included one-by-one based on the specific functionality of this library being used (this might somewhat reduce compilation time). +Alternatively, all =boost/contract/*.hpp= headers are independent from one another and they can be selectively included one-by-one based on the specific functionality of this library being used. +[footnote +In theory, this could reduce compilation time a bit... but in practise it is largely a matter of preference so programmers are not discouraged from simply using `#include `. +] The =boost/contract/core/*.hpp= headers are not independent from other headers and they do not need to be directly included in user code when =boost/contract.hpp= or =boost/contract/*.hpp= headers are included already. All files under =boost/contract/detail/=, names in the `boost::contract::detail` namespace, macros starting with `BOOST_CONTRACT_DETAIL...`, and all names starting with `boost_contract_detail...` (in any namespace, including user-defined namespaces) are part of this library implementation and should never be used directly in user code. - Names starting with `BOOST_CONTRACT_ERROR...` are used by this library to report some compile-time errors (so spotting these names in compiler error messages might help troubleshooting). [endsect] diff --git a/doc/introduction.qbk b/doc/introduction.qbk index 4001b6c..710e8b7 100644 --- a/doc/introduction.qbk +++ b/doc/introduction.qbk @@ -15,7 +15,8 @@ For example, consider the following function `inc` that increments its argument [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/ `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 did not throw an exception). +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 did 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__): @@ -24,9 +25,9 @@ Now let's program this function and its contract using this library (see [@../.. When the above function `inc` is called, this library will: -* First, execute the functor passed to `.precondition(...)` that asserts `inc` preconditions. +* 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` postconditions (unless `inc` body threw an exception). +* 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::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): @@ -37,15 +38,15 @@ precondition assertion "x < std::numeric_limits::max()" failed: file "intro 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 code, function bodies are rarely this simple and can hide bugs that make checking postconditions useful. +In real code, function bodies are rarely this simple and can hide bugs which makes 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_Failure__). -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 the contract assertions fail. +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. @@ -53,10 +54,10 @@ The assertion failure message printed by this library follows a format similar t [note C++11 lambda functions are necessary to use this library without manually writing a significant amount of boiler-plate code to program the functors that assert the contracts (see __No_Lambda_Functions__). -Otherwise, this library does not use other C++11 features and should work on most modern C++ compilers (see __Getting_Started__). +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 simple non-member functions as shown the in the example above, this library allows to program contracts for constructors, destructors, and member functions. +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 code. @@ -74,7 +75,8 @@ Unfortunately, detailed and complete proposals to add contracts to the C++ stand [footnote The authors find attractive the syntax that uses C++11 attributes `[[...]]` to specify contracts as indicated in __P0380__. ] -In any case, at least for now __P0380__ only supports pre- and postconditions while lacking basic features such as class invariants and old values in postconditions, not to mention the lack of more advanced features like subcontracting, all these 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 in designing and implementing this library including the vast majority of contract programming proposals submitted to the C++ standard committee). +In any case, at least for now __P0380__ only supports pre- and postconditions while missing basic features such as class invariants and old values in postconditions, not to mention the lack of more advanced features like subcontracting. +All these 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] diff --git a/doc/main.qbk b/doc/main.qbk index 65977db..99cba79 100644 --- a/doc/main.qbk +++ b/doc/main.qbk @@ -6,10 +6,12 @@ [library Boost.Contract [quickbook 1.5] - [version 0.5.0] + [version 1.0.0] + [purpose Contract programming for C++.] [authors [Caminiti lorcaminiti@gmail.com, Lorenzo]] [copyright 2008-2017 Lorenzo Caminiti] [license 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])] + [source-mode c++] ] [def __Introduction__ [link boost_contract.introduction Introduction]] @@ -28,15 +30,15 @@ [def __Constructor_Calls__ [link boost_contract.contract_programming_overview.constructor_calls Constructor Calls]] [def __Destructor_Calls__ [link boost_contract.contract_programming_overview.destructor_calls Destructor Calls]] [def __Constant_Correctness__ [link boost_contract.contract_programming_overview.constant_correctness Constant-Correctness]] -[def __Specification_vs_Implementation__ [link boost_contract.contract_programming_overview.specification_vs__implementation Specification vs. Implementation]] -[def __On_Contract_Failure__ [link boost_contract.contract_programming_overview.on_contract_failure On Contract Failure]] +[def __Specifications_vs_Implementation__ [link boost_contract.contract_programming_overview.specifications_vs__implementation Specifications vs. Implementation]] +[def __On_Contract_Failures__ [link boost_contract.contract_programming_overview.on_contract_failures On Contract Failures]] [def __Feature_Summary__ [link boost_contract.contract_programming_overview.feature_summary Feature Summary]] [def __Tutorial__ [link boost_contract.tutorial Tutorial]] [def __Non_Member_Functions__ [link boost_contract.tutorial.non_member_functions Non-Member Functions]] [def __Preconditions__ [link boost_contract.tutorial.preconditions Preconditions]] [def __Postconditions__ [link boost_contract.tutorial.postconditions Postconditions]] -[def __Return_Value__ [link boost_contract.tutorial.return_value Return Value]] +[def __Return_Values__ [link boost_contract.tutorial.return_values Return Values]] [def __Old_Values__ [link boost_contract.tutorial.old_values Old Values]] [def __Exception_Guarantees__ [link boost_contract.tutorial.exception_guarantees Exception Guarantees]] [def __Class_Invariants__ [link boost_contract.tutorial.class_invariants Class Invariants]] @@ -52,7 +54,7 @@ [def __Advanced__ [link boost_contract.advanced Advanced]] [def __Pure_Virtual_Public_Functions__ [link boost_contract.advanced.pure_virtual_public_functions Pure Virtual Public Functions]] -[def __Optional_Return_Value__ [link boost_contract.advanced.optional_return_value Optional Return Value]] +[def __Optional_Return_Values__ [link boost_contract.advanced.optional_return_values Optional Return Values]] [def __Private_and_Protected_Functions__ [link boost_contract.advanced.private_and_protected_functions Private and Protected Functions]] [def __Friend_Functions__ [link boost_contract.advanced.friend_functions Friend Functions]] [def __Function_Overloads__ [link boost_contract.advanced.function_overloads Function Overloads]] @@ -62,8 +64,8 @@ [def __Old_Copies_at_Body__ [link boost_contract.advanced.old_copies_at_body Old Copies at Body]] [def __Named_Overrides__ [link boost_contract.advanced.named_overrides Named Overrides]] [def __Access_Specifiers__ [link boost_contract.advanced.access_specifiers Access Specifiers]] -[def __Throw_on_Failure__ [link boost_contract.advanced.throw_on_failure__and__noexcept__ Throw on Failure]] -[def __Throw_on_Failure_and_noexcept__ [link boost_contract.advanced.throw_on_failure__and__noexcept__ Throw on Failure (and `noexcept`)]] +[def __Throw_on_Failures__ [link boost_contract.advanced.throw_on_failures__and__noexcept__ Throw on Failures]] +[def __Throw_on_Failures_and_noexcept__ [link boost_contract.advanced.throw_on_failures__and__noexcept__ Throw on Failures (and `noexcept`)]] [def __Extras__ [link boost_contract.extras Extras]] [def __Old_Value_Requirements__ [link boost_contract.extras.old_value_requirements__templates_ Old Value Requirements]] @@ -130,7 +132,7 @@ This library implements Design by Contract (DbC) is a registered trademark of the Eiffel Software company and it was first introduced by the Eiffel programming language (see __Meyer97__). ] for the C++ programming language. -All contract programming features are supported by this library: subcontracting, class invariants (also for static and volatile member functions), postconditions (with old and return values), preconditions, customizable actions on assertion failure (e.g., terminate the program or throw exceptions), optional compilation of assertions, disable assertions while already checking other assertions (to avoid infinite recursion), and more (see __Feature_Summary__). +All contract programming features are supported by this library: Subcontracting, class invariants (also for static and volatile member functions), postconditions (with old and return values), preconditions, customizable actions on assertion failure (e.g., terminate the program or throw exceptions), optional compilation of assertions, disable assertions while already checking other assertions (to avoid infinite recursion), and more (see __Feature_Summary__). [include introduction.qbk] [include full_table_of_contents.qbk] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index b668173..ea086ac 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -23,9 +23,15 @@ It is possible to specify preconditions, postconditions, and exception guarantee The [funcref boost::contract::function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). [footnote -The name of this local variable is arbitrary, but `c` is often used in this documentation (for ["c]heck, or ["c]aminiti [^;-)]). +The name of this local variable is arbitrary, but `c` is often used in this documentation for ["c]heck or ["c]aminiti [^;-)]. +] +Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). +[footnote +*Rationale:* +C++17 zero-copy guarantee on function return values skips the trick this library uses to force a compile-time error when `auto` is incorrectly used instead of [classref boost::contract::check]. +The library is still able to generate a run-time error in this case on C++17. +In any case, after reading this documentation it should be evident to programmers that `auto` should not be used in [classref boost::contract::check] declarations so this misuse of `auto` should not be an issue in practice. ] -Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error). The function body is programmed right after the declaration of the RAII object. [note @@ -64,15 +70,19 @@ C++11 lambda functions are convenient to program preconditions, but any other nu Lambda functions with no parameters can be programmed in C++11 as `[...] () { ... }` but also equivalently as `[...] { ... }`. This second from is often used in this documentation omitting the empty parameter list `()` for brevity. ] -For example, for [funcref boost::contract::function] (same for public functions, but destructors do not have preconditions and constructors use [classref boost::contract::constructor_precondition] instead, see __Destructors__ and __Constructors__): +For example, for [funcref boost::contract::function] (similarly for public functions, instead destructors do not have preconditions and constructors use [classref boost::contract::constructor_precondition], see __Public_Functions__, __Destructors__, and __Constructors__): - boost::contract::check c = boost::contract::function() // Same for all other contracts. - .precondition([&] { // Capture by reference or value... - BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + void f(...) { + boost::contract::check c = boost::contract::function() // Same for all other contracts. + .precondition([&] { // Capture by reference or value... + BOOST_CONTRACT_ASSERT(...); // ...and should not modify captures. + ... + }) ... - }) + ; + ... - ; + } The precondition functor should capture all the variables that it needs to assert the preconditions. These variables can be captured by value when the overhead of copying such variables is acceptable. @@ -82,19 +92,19 @@ In this documentation preconditions often capture variables by reference to avoi In any case, precondition assertions should not modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__). Any code can be programmed in the precondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex preconditions that might be buggy and also slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program precondition assertions because this enables the library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program precondition assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition contains commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. + BOOST_CONTRACT_ASSERT(bool_cond) + // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call the failure handler [funcref boost::contract::precondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if calling the functor specified to `.precondition(...)` throws any exception. -By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failure__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). +This library will automatically call the failure handler [funcref boost::contract::precondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if calling the functor specified via `.precondition(...)` throws any exception. +By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). [note Contracts are most useful when their assertions only use public members that are accessible to the caller so the caller can properly check and use the contract. In particular, preconditions of a public function or constructor that use non-public members are essentially incorrect because they cannot be fully checked by the caller (in fact, Eiffel generates a compile-time error in this case). -However, this library does not enforce such a constraint and it leaves it up to programmers to only use public members when programming contracts, and especially when asserting preconditions (see __Specification_vs_Implementation__). +However, this library does not enforce such a constraint and it leaves it up to programmers to only use public members when programming contracts, especially when asserting preconditions (see __Specifications_vs_Implementation__). ] [endsect] @@ -106,65 +116,73 @@ Contracts that do not have postconditions simply do not call `.postcondition(... Postconditions must appear after preconditions but before exception guarantees when these are all present (see __Preconditions__ and __Exception_Guarantees__). C++11 lambda functions are convenient to program postconditions, but any other nullary functor can be used (see __No_Lambda_Functions__). -For example, for [funcref boost::contract::function] (but same for all other contracts): +For example, for [funcref boost::contract::function] (similarly for all other contracts): - boost::contract::check c = boost::contract::function() // Same for all other contracts. - ... - .postcondition([&] { // Capture by reference... - BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + void f(...) { + boost::contract::check c = boost::contract::function() // Same for all other contracts. ... - }) + .postcondition([&] { // Capture by reference... + BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + ... + }) + ... + ; + ... - ; + } The postcondition functor should capture all variables that it needs to assert the postconditions. In general, these variables should be captured by reference and not by value (because postconditions need to access the value that these variables will have at function exit, and not the value these variables had when the postcondition functor was first constructed). -Postconditions can also capture return and old values (see __Return_Value__ and __Old_Values__). +Postconditions can also capture return and old values (see __Return_Values__ and __Old_Values__). In any case, postcondition assertions should not modify the value of the captured variables (see __Constant_Correctness__). Any code can be programmed in the postcondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex postconditions that might be buggy and slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program postcondition assertions because this enables the library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program postcondition assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. + BOOST_CONTRACT_ASSERT(bool_cond) + // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). This library will automatically call the failure handler [funcref boost::contract::postcondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if calling the functor specified via `.postcondition(...)` throws any exception. -By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failure__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). +By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). For non-void virtual public functions and public function overrides, the functor [^['s]] passed to `.postcondition(`[^['s]]`)` is not a nullary functor, instead it is a unary functor taking a variable holding the return value as its one parameter [^['s]]`(`[^['result]]`)` (this is to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). [endsect] -[section Return Value] +[section Return Values] -In non-void functions, postconditions can access the function return value to program assertions. -In this case, programmers are responsible to declare a local variable before the contract and to assign it to the return value at function exit (when the function does not throw an exception). +In non-void functions, postconditions might need to access the function return value to program assertions. +In these cases, programmers are responsible to declare a local variable before the contract and to assign it to the return value at function exit (when the function does not throw an exception). [footnote The name of the local variable that holds the return value is arbitrary, but `result` is often used in this documentation. ] -For example, for [funcref boost::contract::function] (but same for all other contracts): +For example, for [funcref boost::contract::function] (similarly for all other contracts): - ``/return-type/`` result; // Must be assigned to return value. - boost::contract::check c = boost::contract::function() // Same for all other contracts. - ... - .postcondition([&] { // Also capture `result` reference... - BOOST_CONTRACT_ASSERT(result ...); // ...but should not modify captures. + return_type f(...) { + return_type result; // Must be later assigned to return value. + boost::contract::check c = boost::contract::function() // Same for all other contracts. ... - }) - ... - ; + .postcondition([&] { // Also capture `result` reference... + BOOST_CONTRACT_ASSERT(result ...); // ...but should not modify captures. + ... + }) + ... + ; + + ... // Assign `result` at each return. + } At any point where the enclosing function returns, programmers are responsible to assign the result variable to the expression being returned. -This can be easily done by making sure that /all/ `return` statements in the function are of the form: +This can be done ensuring that /all/ `return` statements in the function are of the form: - return result = ``/expression/``; // Assign `result` at each return. + return result = return_expr; // Assign `result` at each return. The functor used to program postconditions should capture the result variable by reference and not by value (because postconditions must access the value the result variable will have at function exit, and not the value the result variable had when the postcondition functor was first constructed). The return value should never be used in preconditions, old value copies, or exception guarantees (because the return value is not yet correctly evaluated and set when preconditions are checked, old values are copied, or if the function throws an exception). In any case, programmers should not modify the result variable in the contract assertions (see __Constant_Correctness__). -It is also possible to declared the result variable using `boost::optional` when the function return type does not have a default constructor, or if the default constructor is too expensive or undesirable to execute when declaring the result variable (see __Optional_Return_Value__). +It is also possible to declared the result variable using `boost::optional` when the function return type does not have a default constructor, or if the default constructor is too expensive or undesirable to execute when first declaring the result variable (see __Optional_Return_Values__). Non-void virtual public functions and public function overrides must always declare and use a result variable even when postconditions do not directly use the function return value (this is to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). @@ -176,33 +194,39 @@ When old values are used in postconditions or in exception guarantees, programme [footnote The name of a local variable that holds an old value is arbitrary, but [^old_['variable-name]] is often used in this documentation. ] -For example, for [funcref boost::contract::function] (but same for all other contracts): +For example, for [funcref boost::contract::function] (similarly for all other contracts): + + void f(...) { + boost::contract::old_ptr old_var = BOOST_CONTRACT_OLDOF(old_expr); + ... // More old value declarations here if needed. + boost::contract::check c = boost::contract::function() // Same for all other contracts. + ... // Preconditions shall not use old values. + .postcondition([&] { // Capture by reference... + BOOST_CONTRACT_ASSERT(*old_var ...); // ...but should not modify captures. + ... + }) + .except([&] { // Capture by reference... + BOOST_CONTRACT_ASSERT(old_var->...); // ...but should not modify captures. + ... + }) + ; - boost::contract::old_ptr<``/type/``> old_``/name/`` = BOOST_CONTRACT_OLDOF(``/expression/``); - boost::contract::check c = boost::contract::function() // Same for all other contracts. ... - .postcondition([&] { // Capture by reference... - BOOST_CONTRACT_ASSERT(*old_``/name/`` ...); // ...but should not modify captures. - ... - }) - .except([&] { // Capture by reference... - BOOST_CONTRACT_ASSERT(*old_``/name/`` ...); // ...but should not modify captures. - ... - }) - ; + } Old values are handled by this library using the smart pointer class template [classref boost::contract::old_ptr] (so programmers do not directly manage allocation and deallocation of the pointed memory). [footnote *Rationale:* -Old values are optional values because they need to be left uninitialized in case postconditions and exception guarantees are disabled defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS] to avoid old value copies in that case (so a pointer or better a `boost::optional` can be used for that). -In addition, old values need to be pointers internally allocated by this library so that they are never copied twice even when calling an overridden function multiple times to check preconditions, postconditions, etc. to implement subcontracting (so a smart pointer class template was used). +Old values have to be optional values because they need to be left uninitialized when they are not used because both postconditions and exception guarantees are disabled (defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS]). +That is to avoid old value copies when old values are not used, so a pointer, or better a `boost::optional`, could have been used for that. +In addition, old values need to be pointers internally allocated by this library so that they are never copied twice even when calling an overridden function multiple times to check preconditions, postconditions, etc. to implement subcontracting, so a smart pointer class template was used. ] -The pointed old value is automatically qualified as `const` (so old values cannot be mistakenly changed by contract assertions, see __Constant_Correctness__). -This library ensures that old value pointers are always not null by the time postconditions and exception guarantees are checked (so programmers can safely dereference these pointers in postcondition and exception guarantee assertions using `operator*` or `operator->` without having to check if old value pointers are not null first). +The pointed old value type is automatically qualified as `const` (so old values cannot be mistakenly changed by contract assertions, see __Constant_Correctness__). +This library ensures that old value pointers are always not null by the time postconditions and exception guarantees are checked (so programmers can safely dereference and use these pointers in postcondition and exception guarantee assertions using `operator*` and `operator->` without having to check if old value pointers are not null first). Old values should not be used in preconditions and this library does not guarantee that old value pointers are always not null when preconditions are checked. [footnote -For example, old value pointers might be null in preconditions when postconditions and exception guarantees are disabled defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS], when checking an overridden virtual public function contract via subcontracting, and possibly in other cases. +For example, old value pointers might be null in preconditions when postconditions and exception guarantees are disabled defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS], but also when checking an overridden virtual public function contract via subcontracting, etc. ] See __Old_Copies_at_Body__ for delaying the assignment of old values until after class invariants (for constructors, destructors, and public functions) and preconditions are checked (this allows to program old value expressions under the simplifying assumption that class invariant and precondition assertions are satisfied already). @@ -224,39 +248,43 @@ Contracts that do not have exception guarantees simply do not call `.except(...) Exception guarantees must appear after both preconditions and postconditions when these are all present (see __Preconditions__ and __Postconditions__). C++11 lambda functions are convenient to program exception guarantees, but any other nullary functor can be used (see __No_Lambda_Functions__). -For example, for [funcref boost::contract::function] (but same for all other contracts): +For example, for [funcref boost::contract::function] (similarly for all other contracts): - boost::contract::check c = boost::contract::function() // Same for all other contracts. - ... - .except([&] { // Capture by reference... - BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + void f(...) { + boost::contract::check c = boost::contract::function() // Same for all other contracts. ... - }) - ; + .except([&] { // Capture by reference... + BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + ... + }) + ; + + ... + } The exception guarantee functor should capture all variables that it needs to assert the exception guarantees. In general, these variables should be captured by reference and not by value (because exception guarantees need to access the value that these variables will have when the function throws, and not the value these variables had when the exception guarantee functor was first constructed). -Exception guarantees can also capture old values (see __Old_Values__) but they should not access the return value instead (because the return value will not be properly set when the function throws an exception). +Exception guarantees can also capture old values (see __Old_Values__) but they should not access the function return value instead (because the return value will not be properly set when the function throws an exception). In any case, exception guarantee assertions should not modify the value of the captured variables (see __Constant_Correctness__). [note In real code, it might be difficult to program meaningful exception guarantees without resorting to expensive old value copies that will slow down execution. Therefore, the authors recognize that exception guarantees, even if supported by this library, might not be used often in practice (and they are not used in most of the examples listed in the rest of this documentation). -Instead, exception guarantees might be useful in those cases when they can be programmed just reusing the old value copies already present because used by postconditions. +In any case, these performance considerations are ultimately left to programmers and their specific application domain. ] Any code can be programmed in the exception guarantee functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex exception guarantees that might be buggy and slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program exception guarantee assertions because this enables the library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program exception guarantee assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. + BOOST_CONTRACT_ASSERT(bool_cond) + // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). This library will automatically call the failure handler [funcref boost::contract::except_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if calling the functor specified via `.except(...)` throws any exception. -By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failure__ to change the failure handler to exit the program with an error code or to take some other custom action). +By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to exit the program with an error code or to take some other custom action). [note -While it is technically possible for programmers to specify an exception guarantee handler that throws an exception in case of an exception guarantee failure, this will force C++ to terminate the program anyway. +While it is technically possible for programmers to specify an exception guarantee handler that throws an exception in case of an exception guarantee failure, this will force C++ to terminate the program. That is because the handler will throw an exception while there is already an active exception on the stack (the exception thrown by the function body that caused the exception guarantees to be checked in the first place). Therefore, programmers should not change the exception guarantee failure handler to throw exceptions. ] @@ -265,6 +293,7 @@ Therefore, programmers should not change the exception guarantee failure handler [section Class Invariants] +Public member functions, constructors, and destructors can be programmed to check class invariants. When class invariants are specified, they are programmed in a public `const` function named `invariant` taking no argument and returning `void`. Classes that do not have invariants, simply do not declare the `invariant` function. [footnote @@ -272,7 +301,7 @@ This library uses template meta-programming (SFINAE-based introspection techniqu ] For example: - class a { + class u { public: // Must be public. void invariant() const { // Must be const. BOOST_CONTRACT_ASSERT(...); @@ -286,14 +315,14 @@ This member function must be `const` because contracts should not modify the obj This library will generate a compile-time error if the `const` qualifier is missing (unless [macroref BOOST_CONTRACT_PERMISSIVE] is defined). Any code can be programmed in the `invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex invariants that might be buggy and slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program class invariant assertions because this enables the library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program class invariant assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. + BOOST_CONTRACT_ASSERT(bool_cond) + // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). This library will automatically call failure handlers [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if the `invariant` function throws an exception when invariants are checked at function entry or exit respectively. -By default, these handlers print an error message to `std::cerr` and terminate the program calling `std::terminate` (see __Throw_on_Failure__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). +By default, these handlers print an error message to `std::cerr` and terminate the program calling `std::terminate` (see __Throw_on_Failures__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). See __Access_Specifiers__ to avoid making the `invariant` member function `public`. [footnote @@ -304,13 +333,14 @@ See [macroref BOOST_CONTRACT_INVARIANT_FUNC] to use a name different from `invar [note Contract assertions are not checked (not even class invariants) when data members are accessed directly (this is different from Eiffel where even accessing public data members checks class invariants). -Therefore, it might be best for both `class`es and `struct`s (and also `union`s, see __Unions__) that have invariants to have no mutable public data members and to access data members publicly only via appropriate public functions (e.g., setters and getters) that can check the class invariants. +Therefore, it might be best for both `class`es and `struct`s (and also `union`s, see __Unions__) that have invariants to have no mutable public data members and to access data members publicly only via appropriate public functions (e.g., setters and getters) that can be programmed to check the class invariants using this library. ] See __Volatile_Public_Functions__ to program invariants for classes with `volatile` public functions. [heading Static Class Invariants] +Static public functions can be programmed to check static class invariants. When static class invariants are specified, they are programmed in a public `static` function named `static_invariant` taking no argument and returning `void`. Classes that do not have static class invariants, simply do not declare the `static_invariant` function. [footnote @@ -318,7 +348,7 @@ This library uses template meta-programming (SFINAE-based introspection techniqu ] For example: - class a { + class u { public: // Must be public. static void static_invariant() { // Must be static. BOOST_CONTRACT_ASSERT(...); @@ -332,14 +362,14 @@ This member function must be `static` (and it correctly cannot access the object This library will generate a compile-time error if the `static` classifier is missing (unless the [macroref BOOST_CONTRACT_PERMISSIVE] macro is defined). Any code can be programmed in the `static_invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex static invariants that might be buggy and slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because this enables the library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(``/boolean-condition/``) + BOOST_CONTRACT_ASSERT(bool_cond) // Or, if condition has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. + BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). This library will automatically call failure handlers [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and, more in general, if the `static_invariant` function throws an exception when invariants are checked at function entry or exit respectively. -By default, these handlers print an error message to `std::cerr` and terminate the program calling `std::terminate` (see __Throw_on_Failure__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). +By default, these handlers print an error message to `std::cerr` and terminate the program calling `std::terminate` (see __Throw_on_Failures__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). See __Access_Specifiers__ to avoid making `static_invariant` member function `public`. [footnote @@ -350,7 +380,7 @@ See [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC] to use a name different from [footnote *Rationale:* In C++, it is not possible to overload a member function based on the `static` classifier. -Therefore, this library has to use different names for the member functions checking non-static and static class invariants (namely [macroref BOOST_CONTRACT_INVARIANT_FUNC] and [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC]). +Therefore, this library has to use different names for the member functions checking non-static and static class invariants (namely for [macroref BOOST_CONTRACT_INVARIANT_FUNC] and for [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC]). ] [endsect] @@ -366,41 +396,44 @@ For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_end] It is not possible to specify preconditions using `.precondition(...)` for constructors (this library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]). -Constructor preconditions are specified using the [classref boost::contract::constructor_precondition] base class instead (but the considerations from __Preconditions__ apply also to the precondition functor passed to [classref boost::contract::constructor_precondition]). +Constructor preconditions are specified using the [classref boost::contract::constructor_precondition] base class instead (but considerations from __Preconditions__ apply also to the precondition functor passed to [classref boost::contract::constructor_precondition]). Programmes should not access the object `*this` from constructor preconditions (because the object does not exists yet before the constructor body is executed). [footnote -See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still not recommended because of extra boiler-plate code). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). ] -Constructors without preconditions simply do not explicitly initialize the [classref boost::contract::constructor_precondition] base (in fact [classref boost::contract::constructor_precondition] default constructor checks no contract). -When [classref boost::contract::constructor_precondition] is used: +Constructors without preconditions simply do not explicitly initialize the [classref boost::contract::constructor_precondition] base (because [classref boost::contract::constructor_precondition] default constructor checks no contract). +When the [classref boost::contract::constructor_precondition] base class is used: [footnote There is a MSVC bug that was fixed in MSVC 2013 for which lambdas cannot be used in constructor member initialization lists for templates. On MSVC compilers with that bug, an extra (static) member function can be used (together with `bind` and `cref` as needed) to program constructor preconditions instead of using lambdas (see __No_Lambda_Functions__). ] * It should be specified as the /first/ class in the inheritance list (so constructor preconditions are checked before initializing any other base class or data member). -* Its inheritance access specifier should always be `private` (so this extra base class does not alter the public inheritance tree of the derived class). -* It takes the derived class as template parameter (the Curiously Recursive Template Pattern (CRTP) is used here to avoid ambiguity errors with multiple inheritance). +* Its inheritance access specifier should always be `private` (so this extra base class does not alter the public inheritance tree of its derived classes). +* It takes the derived class as template parameter (the Curiously Recursive Template Pattern (CRTP) is used here to avoid ambiguity resolution errors with multiple inheritance). [footnote *Rationale:* The [classref boost::contract::constructor_precondition] takes the derived class as its template parameter so the instantiated template type is unique for each derived class. -This always avoids base class ambiguity errors even when multiple inheritance is used. -Note that virtual inheritance could not be used instead of the template parameter here to avoid ambiguity errors (because virtual bases are initialized only once by the out-most derived class, and that would not allow to properly check preconditions of all base classes). +This always avoids base class ambiguity resolution errors even when multiple inheritance is used. +Note that virtual inheritance could not be used instead of the template parameter here to resolve ambiguities (because virtual bases are initialized only once by the outer-most derived class, and that would not allow to properly check preconditions of all base classes). ] [note A class can avoid inheriting from [classref boost::contract::constructor_precondition] for efficiency but only when all its constructors have no preconditions. ] -It is possible to specify postconditions for constructors (see __Postconditions__). -Programmers should not access the old value of the object `*this` in constructor postconditions (because the object did not exist yet before the constructor body was executed). +It is possible to specify postconditions for constructors (see __Postconditions__), but programmers should not access the old value of the object `*this` in constructor postconditions (because the object did not exist yet before the constructor body was executed). [footnote -See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still not recommended because of extra boiler-plate code). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). +] +It is also possible to specify exceptions guarantees for constructors (see __Exception_Guarantees__), but programmers should not access the object `this` or its old value in constructor exception guarantees (because the object did not exist before executing the constructor body and it was not properly constructed given the constructor body threw an exception). +[footnote +See __No_Lambda_Functions__ to enforce these constraints at compile-time (but not recommended because of extra boiler-plate code). ] The [funcref boost::contract::constructor] function takes `this` as a parameter (because constructors check class invariants, see __Class_Invariants__). The [funcref boost::contract::constructor] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). -Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error). +Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). The constructor body is programmed right after the declaration of the RAII object. At construction, the [classref boost::contract::check] RAII object for constructors does the following (enclosing constructor entry): @@ -423,18 +456,18 @@ A constructor can avoid calling [funcref boost::contract::constructor] for effic The default constructor and copy constructor automatically generated by C++ will not check contracts. Therefore, unless these constructors are not public or they have no preconditions, no postconditions, no exception guarantees, and their class has no invariants, programmers should manually define them using [funcref boost::contract::constructor] and [classref boost::contract::constructor_precondition]. -Similar considerations apply to all other constructors automatically generated by C++ (e.g., move constructor). +Similar considerations apply to all other constructors automatically generated by C++ (e.g., the move constructor). ] Private and protected constructors can omit [funcref boost::contract::constructor] (because they are not part of the public interface of the class so they are not required to check class invariants, see __Constructor_Calls__). They could still use [classref boost::contract::constructor_precondition] to check preconditions before member initializations, and even use [funcref boost::contract::function] (but not [funcref boost::contract::constructor]) to only check postconditions and exception guarantees without checking class invariants and without calling `.precondition(...)` (see __Private_and_Protected_Functions__). For example: - class a : private boost::contract::constructor_precondition { + class u : private boost::contract::constructor_precondition { protected: // Contract for a protected constructor (same for private constructors). - a() : // Still use this base class to check constructor preconditions. - boost::contract::constructor_precondition([&] { + u() : // Still use this base class to check constructor preconditions. + boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(...); ... }) @@ -469,16 +502,19 @@ For example (see [@../../example/features/public.cpp =public.cpp=]): [public_destructor] [public_class_end] -It is not possible to specify preconditions for destructors (this library will generate a compile-time error if `.precondition(...)` is used here because destructors can be called at any time after construction so they have no precondition). -It is possible to specify postconditions for destructors (see __Postconditions__, and also __Static_Public_Functions__ for an example). -Programmers should not access the object `*this` in destructor postconditions (because the object no longer exists after the destructor body has been executed). +It is not possible to specify preconditions for destructors (this library will generate a compile-time error if `.precondition(...)` is used here and that is because destructors can be called at any time after construction so they have no precondition). +It is possible to specify postconditions for destructors (see __Postconditions__, and also __Static_Public_Functions__ for an example), but programmers should not access the object `this` in destructor postconditions (because the object no longer exists after the destructor body has been executed). [footnote -See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still not recommended because of extra boiler-plate code). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). +] +It is also possible to specify exceptions guarantees for destructors (see __Exception_Guarantees__, even if destructors should usually be programmed to not throw exceptions in C++ and in fact they are implicitly declared `noexcept` since C++11). +[footnote +Exceptions guarantees in destructors can access both the object `this` and its old value because the object exited before executing the destructor body and it still exists given the destructor body failed throwing an exception so the object should still be properly constructed and satisfy its class invariants. ] The [funcref boost::contract::destructor] function takes `this` as a parameter (because destructors check class invariants, see __Class_Invariants__). The [funcref boost::contract::destructor] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). -Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error). +Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). The destructor body is programmed right after the declaration of the RAII object. At construction, the [classref boost::contract::check] RAII object for destructors does the following (enclosing destructor entry): @@ -507,10 +543,10 @@ Private and protected destructors can omit [funcref boost::contract::destructor] They could use [funcref boost::contract::function] (but not [funcref boost::contract::destructor]) to only check postconditions and exception guarantees without checking class invariants and without calling `.precondition(...)` (see __Private_and_Protected_Functions__). For example: - class a { + class u { protected: // Contract for a protected destructor (same for private destructors). - virtual ~a() { + virtual ~u() { // Following will correctly not check class invariants. boost::contract::check c = boost::contract::function() // Do not use `.precondition(...)` here. @@ -518,6 +554,7 @@ For example: BOOST_CONTRACT_ASSERT(...); ... }) + // Could use `.except(...)` here in rare cases of destructors declared to throw. ; ... // Destructor body. @@ -542,7 +579,7 @@ It is possible to specify preconditions, postconditions, and exception guarantee When called from non-static public functions, the [funcref boost::contract::public_function] function takes `this` as a parameter (because public functions check class invariants, see __Class_Invariants__). The [funcref boost::contract::public_function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). -Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error). +Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). The public function body is programmed right after the declaration of the RAII object. At construction, the [classref boost::contract::check] RAII object for public functions does the following (enclosing public function entry): @@ -565,7 +602,7 @@ A public function can avoid calling [funcref boost::contract::public_function] f The default copy assignment operator automatically generated by C++ will not check contracts. Therefore, unless this operator is not public or it has no preconditions, no postconditions, no exception guarantees, and its class has no invariants, programmers should manually define it using [funcref boost::contract::public_function]. -Similar considerations apply to all other operations automatically generated by C++ (move operator, etc.). +Similar considerations apply to all other operators automatically generated by C++ (e.g., the move operator). ] [endsect] @@ -584,7 +621,7 @@ Virtual public functions must declare an extra trailing parameter of type [class [footnote The name of this extra parameter is arbitrary, but `v` is often used in this documentation. ] -This extra parameter is the last parameter and it has a default value so it does not alter the calling interface of the virtual function (in practice, callers will rarely, if ever, have to explicitly deal with this extra parameter, a part from when manipulating the virtual function type directly for function pointer type-casting, etc.). +This extra parameter is the last parameter and it has a default value so it does not alter the calling interface of the virtual function (callers will rarely, if ever, have to explicitly deal with this extra parameter a part from when manipulating the virtual function type directly for function pointer type-casting, etc.). Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the virtual public function definition. [footnote *Rationale:* @@ -595,12 +632,22 @@ Furthermore, this parameter is internally used by this library to pass result an When called from virtual public functions, the [funcref boost::contract::public_function] function takes `this` as a parameter (because public functions check class invariants, see __Class_Invariants__). For virtual public functions returning `void`: - // In a void virtual public function (that does not override). - boost::contract::check c = boost::contract::public_function(v, this) // No result parameter... - .precondition([&] { ... }) - .postcondition([&] { ... }) // ...so nullary functor. - .except([&] { ... }) - ; + class u { + public: + // A void virtual public function (that does not override). + virtual void f(t_1 a_1, ..., t_n a_n, boost::contract::virtual_* v = 0) { + boost::contract::check c = boost::contract::public_function( + v, this) // No result parameter... + .precondition([&] { ... }) + .postcondition([&] { ... }) // ...so nullary functor. + .except([&] { ... }) + ; + + ... + } + + ... + } For virtual public functions not returning `void`, programmers must also pass a reference to the function return value as the second argument to [funcref boost::contract::public_function]. In this case, the library will pass this return value reference to the postcondition functor that must therefore take one single argument matching the return type, otherwise this library will generate a compile-time error (the functor parameter can be a constant reference `const&` to avoid extra copies of the return value): @@ -609,13 +656,23 @@ In this case, the library will pass this return value reference to the postcondi The extra function result parameter taken by the functor passed to `.postcondition(...)` is used by this library to pass the return value evaluated by the overriding function to all its overridden virtual functions when subcontracting. ] - // In a non-void virtual public function (that does not override). - ``['return-type]`` result; - boost::contract::check c = boost::contract::public_function(v, result, this) // Result parameter... - .precondition([&] { ... }) - .postcondition([&] (``['return-type]`` const& result) { ... }) // ...so unary functor. - .except([&] { ... }) - ; + class u { + public: + // A void virtual public function (that does not override). + virtual r f(t_1 a_1, ..., t_n a_n, boost::contract::virtual_* v = 0) { + r result; + boost::contract::check c = boost::contract::public_function( + v, result, this) // Result parameter... + .precondition([&] { ... }) + .postcondition([&] (r const& result) { ... }) // ...so unary functor. + .except([&] { ... }) + ; + + ... // Assign `result` at each return. + } + + ... + } [important It is the responsibility of the programmers to pass the extra virtual parameter `v` to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls within virtual public functions, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void virtual public functions. @@ -627,9 +684,9 @@ Therefore, this library does not know if the enclosing function has a non-void r Instead the function type is passed to this library for virtual public function overrides and that also allows this library to give a compile-time error if the return value reference is missing in those cases. ] -Mnemonic: +*Mnemonics:* [:When `v` is present, always pass it as the first argument to [funcref boost::contract::public_function] and [macroref BOOST_CONTRACT_OLDOF].] -[:Always pass `result` to [funcref boost::contract::public_function] right after `v` (for non-void functions).] +[:Always pass `result` to [funcref boost::contract::public_function] right after `v` for non-void functions.] ] For the rest, considerations made in __Public_Functions__ apply to virtual public functions as well. @@ -647,7 +704,7 @@ In this section, let's consider public functions (virtual or not) that override For example (see [@../../example/features/public.cpp =public.cpp=]): [footnote In this documentation, function overrides are often marked with the code comment `/* override */`. -On compilers that support C++11 virtual specifiers, the `override` identifier can be used instead (`override` is not used in the documentation only because virtual specifiers are not widely supported yet, even by compilers that support C++11 lambda functions). +On compilers that support C++11 virtual specifiers, the `override` identifier can be used instead (`override` is not used in the documentation simply because virtual specifiers are not widely supported yet, even by compilers that support C++11 lambda functions). ] [public_derived_class_begin] @@ -658,10 +715,10 @@ The extra `typedef` declared using [macroref BOOST_CONTRACT_BASE_TYPES] is requi When called from public function overrides, the [funcref boost::contract::public_function] function template takes an explicit template argument `override_`[^['function-name]] that must be defined using [macroref BOOST_CONTRACT_OVERRIDE]: - BOOST_CONTRACT_OVERRIDE(``['function-name]``) + BOOST_CONTRACT_OVERRIDE(func_name) This can be declared at any point in the public section of the enclosing class (see __Access_Specifiers__ to use [macroref BOOST_CONTRACT_OVERRIDE] in a non-public section of the class instead). -[macroref BOOST_CONTRACT_OVERRIDE] must be used only once in a class for a given function name and overloaded functions can reuse the same [^override_['function-name]] definition (see __Function_Overloads__). +[macroref BOOST_CONTRACT_OVERRIDE] is used only once in a class for a given function name and overloaded functions can reuse the same [^override_['function-name]] definition (see __Function_Overloads__). [macroref BOOST_CONTRACT_NAMED_OVERRIDE] can be used to generate a name different than [^override_['function-name]] (e.g., to avoid generating C++ reserved names containing double underscores "`__`" for function names that already start with an underscore "`_`", see __Named_Overrides__). For convenience [macroref BOOST_CONTRACT_OVERRIDES] can be used with multiple function names instead of repeating [macroref BOOST_CONTRACT_OVERRIDE] for each function name (on compilers that support variadic macros). For example, for three functions named `f`, `g`, and `h` (but same for any other number of functions), the following: @@ -688,39 +745,57 @@ Programmers must pass the extra virtual parameter as the very first argument to When called from public function overrides, the [funcref boost::contract::public_function] function takes a pointer to the enclosing function, the object `this` (because public function overrides check class invariants, see __Class_Invariants__), and references to each function argument in the order they appear in the function declaration. [footnote *Rationale:* -The object `this` is passed after the function pointer to follow `bind`'s syntax. +The object `this` is passed after the function pointer to follow `std::bind`'s syntax. The function pointer and references to all function arguments are needed for public function overrides because this library has to call overridden virtual public functions to check their contracts for subcontracting (even if this library will not actually execute the bodies of the overridden functions). ] For public function overrides returning `void`: - // In a void public function override. - boost::contract::check c = boost::contract::public_function( - v, &``['class-name]``::``['function-name]``, this, // No result parameter... - ``['function-argument_1]``, ``['function-argument_2]``, ... - ) - .precondition([&] { ... }) - .postcondition([&] { ... }) // ...so nullary functor. - .except([&] { ... }) - ; + class u { + public: + // A void public function override. + void f(t_1 a_1, ..., t_n a_n, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function( + v, &u::f, this, a_1, ..., a_n) // No result parameter... + .precondition([&] { ... }) + .postcondition([&] { ... }) // ...so nullary functor. + .except([&] { ... }) + ; + + ... + } + + BOOST_CONTRACT_OVERRIDE(f) + + ... + } For public function overrides not returning `void`, programmers must also pass a reference to the function return value as the second argument to [funcref boost::contract::public_function] (this library will generate a compile-time error otherwise). [footnote *Rationale:* As for non-overriding virtual public functions, also public function overrides use the extra return value parameter to pass it to the overridden functions when subcontracting. -In the case of public function overrides this library also has the function pointer so it will generate a compile-time error if the function is non-void and programmers forget to specify the extra return value parameter (this extra error checking is not possible instead for non-overriding virtual public functions because their contracts do not take the function pointer as a parameter, see __Virtual_Public_Functions__). +In the case of public function overrides, this library has the function pointer so it will generate a compile-time error if the function is non-void and programmers forget to specify the extra return value parameter (this extra error checking is not possible instead for non-overriding virtual public functions because their contracts do not take the function pointer as a parameter, see __Virtual_Public_Functions__). ] In this case, the library will pass this return value reference to the postcondition functor that must therefore take one single argument matching the return type, otherwise this library will generate a compile-time error (the functor parameter can be a constant reference `const&` to avoid extra copies of the return value): - // In non-void public function override. - ``['return-type]`` result; - boost::contract::check c = boost::contract::public_function( - v, result, &``['class-name]``::``['function-name]``, this, // Result parameter... - ``['function-argument_1]``, ``['function-argument_2]``, ... - ) - .precondition([&] { ... }) - .postcondition([&] (``['return-type]`` const& result) { ... }) // ...so unary functor. - .except([&] { ... }) - ; + class u { + public: + // A non-void public function override. + r f(t_1 a_1, ..., t_n a_n, boost::contract::virtual_* v = 0) /* override */ { + r result; + boost::contract::check c = boost::contract::public_function( + v, result, &u::f, this, a_1, ..., a_n) // Result parameter... + .precondition([&] { ... }) + .postcondition([&] (r const& result) { ... }) // ...so unary functor. + .except([&] { ... }) + ; + + ... // Assign `result` at each return. + } + + BOOST_CONTRACT_OVERRIDE(f) + + ... + } This library will throw [classref boost::contract::bad_virtual_result_cast] if programmers specify return values for public function overrides in derived classes that are not consistent with the return types of the virtual public functions being overridden in the base classes. [footnote @@ -732,10 +807,10 @@ The `boost::bad_any_cast` exception could not used here because it does not prin It is the responsibility of the programmers to pass the extra virtual parameter `v` to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls within public function overrides, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void public function overrides. This library cannot always generate compile-time errors if programmers fail to do so (but in general this will prevent the library from correctly checking contracts at run-time). -Mnemonic: +*Mnemonics:* [:When `override_...` is present, always pass it as template parameter to [funcref boost::contract::public_functioon].] [:When `v` is present, always pass it as the first argument to [funcref boost::contract::public_function] and [macroref BOOST_CONTRACT_OLDOF].] -[:Always pass `result` to [funcref boost::contract::public_function] right after `v` (for non-void functions).] +[:Always pass `result` to [funcref boost::contract::public_function] right after `v` for non-void functions.] ] At construction, the [classref boost::contract::check] RAII object for public function overrides does the following (enclosing public function override entry): @@ -780,15 +855,17 @@ As already noted in __Constructors__, when the extra base [classref boost::contr [important Each base passed to [macroref BOOST_CONTRACT_BASE_TYPES] must /explicitly/ specify its inheritance access level `public`, `protected`, or `private` (but `virtual` is optional and can be specified either before or after the access level as usual in C++). +This library will generate a compile-time error if the first base is missing its inheritance access level, but this library will not be able to always generate an error if the access level is missing for bases after the first one. [footnote *Rationale:* This library explicitly requires the inheritance access level because derived classes must subcontract only from public bases, but not from protected or private bases (see __Public_Function_Calls__). -Therefore, [macroref BOOST_CONTRACT_BASE_TYPES] inspects each inheritance access level (using preprocessor meta-programming) and removes non-public bases from the list of bases inspected for subcontracting (i.e., from `base_types`). +[macroref BOOST_CONTRACT_BASE_TYPES] inspects each inheritance access level using preprocessor meta-programming and removes non-public bases from the list of bases inspected for subcontracting. +However, this library cannot always detect when programmers forget to specify the inheritance access level because, when commas are used to separate template parameters passed to base classes, the preprocessor will not be able to correctly use commas to identify the next base class token in the inheritance list (the preprocessor cannot distinguish between commas that are not wrapped within round parenthesis, like the ones used in templates). +Therefore, this library relies on inheritance access levels to program the preprocessor to correctly identify the next base class token in the inheritance list (thus inheritance access levels must always be explicit specified by programmers). ] -This library will generate a compile-time error if the first base is missing its inheritance access level, but this library will not be able to always generate an error if the access level is missing for bases after the first one. It is the responsibility of the programmers to make sure that all bases passed to [macroref BOOST_CONTRACT_BASE_TYPES] explicitly specify their inheritance access level (inheritance access levels are instead optional in C++ because `private` is implicitly assumed for `class` types and `public` for `struct` types). -Mnemonic: +*Mnemonics:* [:Always explicitly specify the inheritance access level `public`, `protected`, or `private` for base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES].] ] @@ -811,17 +888,26 @@ For example (see [@../../example/features/static_public.cpp =static_public.cpp=] [static_public] It is possible to specify preconditions, postconditions, and exception guarantees for static public functions (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). -However, when called from static public functions, [funcref boost::contract::public_function] cannot take the object `this` as a parameter (because there is no object `this` in static member functions) so the enclosing class type is is specified as an explicit template parameter (because the class type is necessary to check static class invariants, see __Class_Invariants__): +When called from static public functions, [funcref boost::contract::public_function] cannot take the object `this` as a parameter (because there is no object `this` in static member functions) so the enclosing class type is is specified as an explicit template parameter (the class type is required to check static class invariants, see __Class_Invariants__): - // In a static public function. - boost::contract::check c = boost::contract::public_function<``[^['class-type]]``>() // Explicit class type template parameter. - .precondition([&] { ... }) - .postcondition([&] { ... }) - .except([&] { ... }) - ; + class u { + public: + // A static public function. + static void f() { + boost::contract::check c = boost::contract::public_function() // Class type `u` as explicit template parameter. + .precondition([&] { ... }) + .postcondition([&] { ... }) + .except([&] { ... }) + ; + + ... + } + + ... + }; The [funcref boost::contract::public_function] function returns an RAII object that must be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). -Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error). +Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). The static public functions body is programmed right after the declaration of the RAII object. At construction, the [classref boost::contract::check] RAII object for static public functions does the following (enclosing static public function entry): @@ -837,10 +923,7 @@ At destruction instead (enclosing static public function exit): # Else: # Check exception guarantees, by calling the nullary functor [^['e]]`()` passed to `.except(`[^['e]]`)`. -This ensures that static public function contracts are correctly checked at run-time (see __Public_Function_Calls__). -[footnote -Note that static public functions do not subcontract because they have no object `this` and therefore there is no inheritance. -] +This ensures that static public function contracts are correctly checked at run-time (static public functions do not subcontract because they have no object `this` and therefore there is no inheritance, see __Public_Function_Calls__). [note A static public function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions, no postconditions, no exception guarantees, and its class has no static invariants (the class can still have non-static invariants or base classes instead). diff --git a/example/features/check.cpp b/example/features/check.cpp index 24f891d..7bee9d6 100644 --- a/example/features/check.cpp +++ b/example/features/check.cpp @@ -27,20 +27,15 @@ int gcd(int const a, int const b) { return result = x; } +//[check int main() { - //[check_class - boost::contract::check c = [&] { // Implementation checks via functor. + // Implementation checks (via nullary functor). + boost::contract::check c = [&] { BOOST_CONTRACT_ASSERT(gcd(12, 28) == 4); BOOST_CONTRACT_ASSERT(gcd(4, 14) == 2); }; - //] - - //[check_macro - // Implementation checks via macro (disable run- and compile-time overhead). - BOOST_CONTRACT_CHECK(gcd(12, 28) == 4); - BOOST_CONTRACT_CHECK(gcd(4, 14) == 2); - //] return 0; } +//] diff --git a/example/features/check_macro.cpp b/example/features/check_macro.cpp new file mode 100644 index 0000000..4f17297 --- /dev/null +++ b/example/features/check_macro.cpp @@ -0,0 +1,39 @@ + +// Copyright (C) 2008-2017 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 + +#include + +int gcd(int const a, int const b) { + int result; + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(a > 0); + BOOST_CONTRACT_ASSERT(b > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result <= a); + BOOST_CONTRACT_ASSERT(result <= b); + }) + ; + + int x = a, y = b; + while(x != y) { + if(x > y) x = x - y; + else y = y - x; + } + return result = x; +} + +//[check_macro +int main() { + // Implementation checks (via macro, disable run-/compile-time overhead). + BOOST_CONTRACT_CHECK(gcd(12, 28) == 4); + BOOST_CONTRACT_CHECK(gcd(4, 14) == 2); + + return 0; +} +//] + diff --git a/example/features/code_block.cpp b/example/features/code_block.cpp index 7b6ffd5..5cd7a57 100644 --- a/example/features/code_block.cpp +++ b/example/features/code_block.cpp @@ -18,6 +18,7 @@ int main() { //[code_block /* ... */ + // Contract for a code block. { // Code block entry (check preconditions). boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); @@ -32,6 +33,7 @@ int main() { total += v[0] + v[1] + v[2]; // Code block body. } // Code block exit (check postconditions and exceptions guarantees). + /* ... */ //] diff --git a/example/features/friend.cpp b/example/features/friend.cpp index b661c8c..b281ce1 100644 --- a/example/features/friend.cpp +++ b/example/features/friend.cpp @@ -9,10 +9,10 @@ #include //[friend_byte -class bytes; +class buffer; class byte { - friend bool operator==(bytes const& left, byte const& right); + friend bool operator==(buffer const& left, byte const& right); private: char value_; @@ -26,10 +26,10 @@ public: bool empty() const { return value_ == '\0'; } }; -//[friend_bytes -class bytes { +//[friend_buffer +class buffer { // Friend functions are not member functions... - friend bool operator==(bytes const& left, byte const& right) { + friend bool operator==(buffer const& left, byte const& right) { // ...so check contracts via `function` (which won't check invariants). boost::contract::check c = boost::contract::function() .precondition([&] { @@ -52,16 +52,18 @@ private: public: // Could program invariants and contracts for following too. - explicit bytes(std::string const& values) : values_(values) {} + explicit buffer(std::string const& values) : values_(values) {} bool empty() const { return values_ == ""; } }; int main() { - bytes p("aaa"); + buffer p("aaa"); byte a('a'); assert(p == a); - bytes q("aba"); + + buffer q("aba"); assert(!(q == a)); // No operator!=. + return 0; } diff --git a/example/features/lambda.cpp b/example/features/lambda.cpp index 189fe1f..23ebf03 100644 --- a/example/features/lambda.cpp +++ b/example/features/lambda.cpp @@ -18,8 +18,8 @@ int main() { //[lambda int total = 0; std::for_each(v.cbegin(), v.cend(), + // Contract for a lambda function. [&total] (int const x) { - // Contract for a lambda function. boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() diff --git a/example/features/loop.cpp b/example/features/loop.cpp index 631c597..9879946 100644 --- a/example/features/loop.cpp +++ b/example/features/loop.cpp @@ -17,8 +17,8 @@ int main() { //[loop int total = 0; + // Contract for a for-loop (same for while- and all other loops). for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) { - // Contract for a for-loop (same for while- and all other loops). boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() .precondition([&] { diff --git a/example/features/public.cpp b/example/features/public.cpp index 8ef443d..cb526e7 100644 --- a/example/features/public.cpp +++ b/example/features/public.cpp @@ -10,8 +10,8 @@ #include //[public_class_begin -class unique_identifiers - : private boost::contract::constructor_precondition +class unique_identifiers : + private boost::contract::constructor_precondition { public: void invariant() const { diff --git a/example/features/separate_body.cpp b/example/features/separate_body.cpp index 268d4da..9c66707 100644 --- a/example/features/separate_body.cpp +++ b/example/features/separate_body.cpp @@ -8,31 +8,29 @@ #include //[separate_body_cpp -template -void array::constructor_body(unsigned count) { - for(unsigned i = 0; i < count; ++i) values_[i] = T(); +void iarray::constructor_body(unsigned count) { + for(unsigned i = 0; i < count; ++i) values_[i] = int(); size_ = count; } -template -void array::destructor_body() { delete[] values_; } +void iarray::destructor_body() { delete[] values_; } -template -void array::push_back_body(T const& value) { - values_[size_++] = value; -} +void iarray::push_back_body(int value) { values_[size_++] = value; } /* ... */ //] -template -unsigned array::size_body() const { return size_; } +unsigned iarray::size_body() const { return size_; } +unsigned iarray::capacity_body() const { return capacity_; } int main() { - array a(2); + iarray a(3, 2); + assert(a.capacity() == 3); assert(a.size() == 2); - a.push_back('x'); + + a.push_back(-123); assert(a.size() == 3); + return 0; } diff --git a/example/features/separate_body.hpp b/example/features/separate_body.hpp index 8e359f7..e39b863 100644 --- a/example/features/separate_body.hpp +++ b/example/features/separate_body.hpp @@ -10,52 +10,54 @@ #include //[separate_body_hpp -template -class array : - private boost::contract::constructor_precondition > { +class iarray : + private boost::contract::constructor_precondition { public: void invariant() const { - BOOST_CONTRACT_ASSERT(size() <= MaxSize); + BOOST_CONTRACT_ASSERT(size() <= capacity()); } - explicit array(unsigned count) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(count <= MaxSize); + explicit iarray(unsigned max, unsigned count = 0) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(count <= max); }), - values_(new T[MaxSize]) // Still, member initializations must be here. + // Still, member initializations must be here. + values_(new int[max]), + capacity_(max) { boost::contract::check c = boost::contract::constructor(this) .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() == max); BOOST_CONTRACT_ASSERT(size() == count); }) ; constructor_body(count); // Separate constructor body implementation. } - virtual ~array() { + virtual ~iarray() { boost::contract::check c = boost::contract::destructor(this); // Inv. destructor_body(); // Separate destructor body implementation. } - virtual void push_back(T const& value, boost::contract::virtual_* v = 0) { + virtual void push_back(int value, boost::contract::virtual_* v = 0) { boost::contract::old_ptr old_size = BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { - BOOST_CONTRACT_ASSERT(size() < MaxSize); + BOOST_CONTRACT_ASSERT(size() < capacity()); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == *old_size + 1); }) ; - push_back_body(value); + push_back_body(value); // Separate member function body implementation. } private: // Contracts in class declaration (above), but body implementations are not. - void constructor_body(unsigned count); + void constructor_body(unsigned max, unsigned count); void destructor_body(); - void push_back_body(T const& value); + void push_back_body(int value); /* ... */ //] @@ -67,10 +69,18 @@ public: return size_body(); } + unsigned capacity() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return capacity_body(); + } + private: unsigned size_body() const; + unsigned capacity_body() const; - T* values_; + int* values_; + unsigned capacity_; unsigned size_; }; diff --git a/example/n1962/sqrt.cpp b/example/n1962/sqrt.cpp index 81c75fa..d20bb1b 100644 --- a/example/n1962/sqrt.cpp +++ b/example/n1962/sqrt.cpp @@ -9,23 +9,23 @@ #include #include -double mysqrt(double x, double precision = 1e-6) { - double result; +long lsqrt(long x) { + long result; boost::contract::check c = boost::contract::function() .precondition([&] { - BOOST_CONTRACT_ASSERT(x >= 0.0); + BOOST_CONTRACT_ASSERT(x >= 0); }) .postcondition([&] { - BOOST_CONTRACT_ASSERT(fabs(result * result - x) <= precision); + BOOST_CONTRACT_ASSERT(result * result <= x); + BOOST_CONTRACT_ASSERT((result + 1) * (result + 1) > x); }) ; - return result = sqrt(x); + return result = long(std::sqrt(double(x))); } int main() { - double const precision = 1e-6; - assert(fabs(mysqrt(4.0, precision) - 2.0) <= precision); + assert(lsqrt(4) == 2); return 0; } //] diff --git a/example/n1962/sqrt.d b/example/n1962/sqrt.d index 8ddacf7..0a3ddc3 100644 --- a/example/n1962/sqrt.d +++ b/example/n1962/sqrt.d @@ -9,15 +9,16 @@ -real mysqrt(real x) - in { - assert(x >= 0.0); - } - out(result) { - assert(std.math.fabs(result * result - x) <= 1e-6); - } -body { - return std.math.sqrt(x); +long lsqrt(long x) +in { + assert(x >= 0); +} +out(result) { + assert(result * result <= x); + assert((result + 1) * (result + 1) > x); +} +do { + return cast(long)std.math.sqrt(cast(real)x); }