From 024b5b9bc511809b50c8f45a245104217a6b2d3d Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Wed, 2 Aug 2017 22:45:45 -0700 Subject: [PATCH] reviewed docs up to extra section. renamed DOXYGEN macro with BOOST_CONTRACT_DETAIL_DOXYGEN --- doc/Jamfile.v2 | 5 +- doc/advanced.qbk | 298 +++++++------ doc/contract_programming_overview.qbk | 283 ++++++------ doc/extras.qbk | 196 ++++++--- doc/getting_started.qbk | 54 +-- doc/introduction.qbk | 28 +- doc/main.qbk | 8 +- doc/tutorial.qbk | 414 ++++++++++-------- example/features/check.cpp | 2 +- example/features/code_block.cpp | 8 +- example/features/friend.cpp | 36 +- example/features/ifdef_audit.cpp | 31 +- example/features/introduction.cpp | 2 +- example/features/named_override.cpp | 4 +- example/features/old.cpp | 4 +- example/features/old_if_copyable.cpp | 12 +- example/features/private_protected.cpp | 9 +- .../features/private_protected_virtual.cpp | 8 +- example/features/public.cpp | 8 +- example/features/pure_virtual_public.cpp | 28 +- example/n1962/vector_n1962.hpp | 42 +- include/boost/contract/call_if.hpp | 12 +- include/boost/contract/check.hpp | 10 +- include/boost/contract/core/config.hpp | 28 +- include/boost/contract/core/exception.hpp | 2 +- include/boost/contract/core/specify.hpp | 2 +- include/boost/contract/old.hpp | 4 +- include/boost/contract/public_function.hpp | 4 +- 28 files changed, 840 insertions(+), 702 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 84e90e1..15c7306 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -33,14 +33,15 @@ doxygen reference : "Reference" # Quickbook's Doxygen does not show destructor exception specs. - PREDEFINED="DOXYGEN BOOST_PP_VARIADICS" + PREDEFINED="BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_PP_VARIADICS" MACRO_EXPANSION=YES INCLUDE_PATH="../include" QUIET=YES JAVADOC_AUTOBRIEF=YES WARN_IF_UNDOCUMENTED=NO EXCLUDE_SYMBOLS=std - # Does not work for XML output (use @cond/#ifdef DOXYGEN in code instead). + # Following does not work for XML output... use @cond and/or + # #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN in code instead. EXTRACT_PRIVATE=NO HIDE_UNDOC_MEMBERS=YES HIDE_UNDOC_CLASSES=YES diff --git a/doc/advanced.qbk b/doc/advanced.qbk index 32416c7..4418e26 100644 --- a/doc/advanced.qbk +++ b/doc/advanced.qbk @@ -6,37 +6,49 @@ [section Advanced] -This section illustrates more advanced uses of this library. +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 `virtual ... = 0;` pure virtual function. +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;`. 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. -For example (see also [@../../example/features/pure_virtual_public.cpp =pure_virtual_public.cpp=]): +For example (see [@../../example/features/pure_virtual_public.cpp =pure_virtual_public.cpp=]): [import ../example/features/pure_virtual_public.cpp] -[pure_virtual_public_base] -[pure_virtual_public_impl] -[pure_virtual_public_derived] +[pure_virtual_public_base_begin] +[pure_virtual_public_base_end] +[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 outside of what strictly required by this library). +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++). + +[heading Subcontracting Preconditions Always True/False] -[import ../example/features/named_override.cpp] -[note 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 with the __substitution_principle__. +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: -That said, it is sometimes useful for a base class to declare a pure virtual function with a single precondition `BOOST_CONTRACT_ASSERT(false)` that will always fail. -This indicates that the pure virtual function can never be called unless it is redefined in a derived class (which is always the case with C++ pure virtual functions) and also that the base class designer has intentionally left it up to derived classes to specify preconditions for the pure virtual function in question. -This technique makes 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 also [@../../example/features/named_override.cpp =named_override.cpp=]): + // 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. + }) + ... + ; +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 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=]): + +[import ../example/features/named_override.cpp] [named_override_pure_virtual_assert_false] -] + +That said, the need to declare such a precondition `BOOST_CONTRACT_ASSERT(false)` that will always fail might be an indication that the base class interface is not correctly designed. +In general, the base class interface should still contain all functions (eventually as pure virtual) that are necessary to program its contracts. [endsect] @@ -47,71 +59,76 @@ It is possible to use `boost::optional` to handle return values when programmers *Rationale:* `boost::optional` is used instead of `std::optional` because `std::optional` is not part of C++ standards prior to C++17. ] -For example (see also [@../../example/features/optional_result.cpp =optional_result.cpp=]): +For example (see [@../../example/features/optional_result.cpp =optional_result.cpp=]): [import ../example/features/optional_result.cpp] [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 either 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 preconditions 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 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`. -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. -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). +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). +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: boost::optional<...> result; ... return *(result = ...); // Assign `result` at each return. -[heading Virtual Public Functions] +[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&`. -For example (see also [@../../example/features/optional_result_virtual.cpp =optional_result_virtual.cpp=]): +For example (see [@../../example/features/optional_result_virtual.cpp =optional_result_virtual.cpp=]): [import ../example/features/optional_result_virtual.cpp] [optional_result_virtual] -The inner `const&` in the postcondition functor parameter type `boost::optional<... const&> ...` is mandatory (the outer `const&` in the postcondition functor parameter type `boost::optional<...> const&` is not). +The inner `const&` in the postcondition functor parameter type `boost::optional<... const&> ...` is mandatory (while the outer `const&` in the postcondition functor parameter type `boost::optional<...> const&` is not). [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 prevented from changing it (because of `const`, see also __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. +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. ] [endsect] [section Private and Protected Functions] -Private and protected member 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 also __Function_Calls__). -However, programmers may still want to specify preconditions and postconditions for private and protected member functions if they want to check correctness of their implementation and use from within the class, base classes, and friend classes or functions. -When programmers decide to specify contracts for private and protected member functions, they can use [funcref boost::contract::function] (like for non-member functions). -For example (see also [@../../example/features/private_protected.cpp =private_protected.cpp=]): +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). +For example (see [@../../example/features/private_protected.cpp =private_protected.cpp=]): [import ../example/features/private_protected.cpp] [private_protected] -The same considerations made in __Non_Member_Functions__ apply. -See __Constructors__ and __Destructors__ for notes on how to program contracts for private and protected constructors and destructors instead. +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 member functions are virtual they should still declare the extra parameter of type [classref boost::contract::virtual_]`*` with default value `0` (see __Virtual_Public_Functions__) even if [funcref boost::contract::function] never accepts that parameter as an argument (so this parameter will remain unused and it does not need a name). -Otherwise, the private and protected virtual functions cannot be overridden by public functions in the derived classes that specify contracts for the overriding functions (because C++ uses also default parameters to match signatures of overriding functions). -For example (see also [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): +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). +[footnote +Technically, the extra virtual parameter can still be passed to [macroref BOOST_CONTRACT_OLDF] but that is not necessary and it has no effect so it is not done in this documentation. +] +That is necessary otherwise the private and protected virtual functions cannot be overridden by public functions in derived classes that specify contracts (because the [classref boost::contract::virtual_]`* = 0` parameter has to be part of signatures for public function overrides). +For example (see [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): [import ../example/features/private_protected_virtual.cpp] [private_protected_virtual_counter] -However, public functions in derived classes overriding private or protected virtual functions from base classes will not specify the extra `override_...` template parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected thus not being public they do not participate to subcontracting), for example (see also [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): +However, public functions in derived classes overriding private or protected virtual functions from base classes shall not specify the extra `override_...` template parameter to [funcref boost::contract::public_function] because the overridden functions are private or protected and, not being public, they do not participate to subcontracting (this library will generate a compile-time error if `override_...` is specified because there will be no virtual public function to override from the base class). +For example (see [@../../example/features/private_protected_virtual.cpp =private_protected_virtual.cpp=]): [private_protected_virtual_counter10] Furthermore, using multiple inheritance it is possible to override functions that are private or protected from one base but public from another base. -In this case, overriding public functions in derived classes will specify the extra `override_...` template parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected in one base and those do not participate to subcontracting, but public in another base and these participate to subcontracting instead). -For example (see also [@../../example/features/private_protected_virtual_multi.cpp =private_protected_virtual_multi.cpp=]): +In this case, public function overrides in derived classes will specify the extra `override_...` template parameter to [funcref boost::contract::public_function] (because the overridden functions are private or protected in one base and those do not participate to subcontracting, but public in another base and these participate to subcontracting instead). +For example (see [@../../example/features/private_protected_virtual_multi.cpp =private_protected_virtual_multi.cpp=]): [import ../example/features/private_protected_virtual_multi.cpp] [private_protected_virtual_multi_countable] @@ -119,9 +136,8 @@ For example (see also [@../../example/features/private_protected_virtual_multi.c [warning Unfortunately, the code above does not compile on MSVC (at least up to Visual Studio 2015) because MSVC incorrectly gives a compile-time error when SFINAE fails due to private or protected access levels. -Instead, GCC and Clang correctly implement SFINAE failures due to private and protected member functions so the code above correctly complies on GCC and Clang. - -Therefore, currently it is not possible to override a member that is public in one base but private or protected in other base using this library on MSVC, that can be done instead on GCC or CLang. +Instead, GCC and Clang correctly implement SFINAE failures due to private and protected functions so the code above correctly complies on GCC and Clang. +Therefore, currently it is not possible to override a function that is public in one base but private or protected in other base using this library on MSVC, but that can be done on GCC or CLang instead. ] [endsect] @@ -129,21 +145,21 @@ Therefore, currently it is not possible to override a member that is public in o [section Friend Functions] Friend functions are not member functions so [funcref boost::contract::function] can used to program contracts for them and all considerations made in __Non_Member_Functions__ apply. -For example (see also [@../../example/features/friend.cpp =friend.cpp=]): +For example (see [@../../example/features/friend.cpp =friend.cpp=]): [import ../example/features/friend.cpp] -[friend_byte] [friend_bytes] +[friend_byte] -However, in some cases a friend function might take an object as parameter and it can be logically considered an extension of the object's public interface (essentially at the same level as the object's public member 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 (and not just the pre- and postconditions of the friend function). -For example (see also [@../../example/features/friend_invariant.cpp =friend_invariant.cpp=]): +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). +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 allow contracts to recognize that some friend functions logically act as if they were part of the public interface of the objects they take as parameters. -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. -However, this library (not being meant to be a revision of the C++ standard itself) has the flexibility to let programmers manually specify when friend functions should also check class invariants of the objects they take 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. +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). ] [import ../example/features/friend_invariant.cpp] @@ -151,8 +167,9 @@ However, this library (not being meant to be a revision of the C++ standard itse This technique can also be extended to friend functions that take multiple objects as parameters and can be logically considered extensions to the public interfaces of each of these objects, for example: + // Can be considered an extension of multiple objects' public interfaces. friend void f(class1& object1, class2* object2, type3& value3) { - // Check just preconditions. + // Check preconditions. boost::contract::check pre = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(object2 != nullptr); @@ -162,19 +179,21 @@ This technique can also be extended to friend functions that take multiple objec // Check class invariants for each object (programmers chose the order). boost::contract::check inv1 = boost::contract::public_function(&object1); boost::contract::check inv2 = boost::contract::public_function(object2); - // Check just postconditions. - boost::contract::check post = boost::contract::function() + // Check postconditions and exception guarantees. + boost::contract::check post_except = boost::contract::function() .postcondition(...) + .except(...) ; ... // 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 pre- and postconditions 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 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). The example above is programmed to check `class1` invariants before `class2` invariants (but the order could have been inverted if programmers so chose). -Also the example above is programmed to check preconditions before class invariants so the objects passed to the friend function can be validated by the preconditions before they are passed as pointers to [funcref boost::contract::public_function] (e.g., check `object2` is not null). -[footnote -Within member functions instead the object pointer `this` is always well-formed, its validation is never needed, and [funcref boost::contract::public_function] checks class invariants before checking preconditions so programming preconditions can be simplified assuming the class invariants are satisfied already (see __Public_Function_Calls__). + +[note +In the example above, preconditions are intentionally programmed to be checked before class invariants so the objects passed to the friend function can be validated by the preconditions before they are passed as pointers to [funcref boost::contract::public_function] (e.g., check `object2` is not null). +(Within member functions instead, the object pointer `this` is always well-formed, its validation is never needed, and [funcref boost::contract::public_function] checks class invariants before checking preconditions so programming preconditions can be simplified assuming the class invariants are satisfied already, see __Public_Function_Calls__.) ] [endsect] @@ -187,51 +206,51 @@ When names of public function overrides are overloaded, the function pointer can *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. Therefore, the library cannot differentiate when the actual function argument and return types are passed by reference and when they are not. -As a result, the library cannot automatically reconstruct the type of the enclosing public function so this type must be deduced from the function pointer explicitly passed by programmers to [funcref boost::contract::public_function]. +As a result, the library cannot automatically reconstruct the type of the enclosing public function so this type must be deduced from the function pointer passed by programmers to [funcref boost::contract::public_function]. When this automatic deduction is not possible due to overloaded function names, programmers must explicitly use `static_cast` to resolve ambiguities as usual in C++ with pointers to overloaded functions. ] -For example, note how `static_cast` is used in the following calls to [funcref boost::contract::public_function] (see also [@../../example/features/overload.cpp =overload.cpp=]): +For example, note how `static_cast` is used in the following calls to [funcref boost::contract::public_function] (see [@../../example/features/overload.cpp =overload.cpp=]): [import ../example/features/overload.cpp] [overload] -Overloaded functions have the same function name so the same [^override_['function-name]] type can be used 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 the function name is overloaded (as shown in the example above). +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. [endsect] [section Lambdas, Loops, Code Blocks (and `constexpr`)] -So far we have been focused on specifying contracts for function and class interfaces. -While contracts are in general most useful when used to specify interfaces, this library also allows to check contract conditions for implementation code (lambda functions, code blocks, loops, etc.). +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 a class public interface so they do not check class invariants or participate int subcontracting, but they can use [funcref boost::contract::function] to specify preconditions, postconditions, and exception guarantees (all considerations made in __Non_Member_Functions__ apply). -For example (see also [@../../example/features/lambda.cpp =lambda.cpp=]): +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. +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=]): [import ../example/features/lambda.cpp] [lambda] Similarly, [funcref boost::contract::function] can be used to program preconditions, postconditions, and exception guarantees for loops. -For example, for a for-loop but same for while- and all other loops (see also [@../../example/features/loop.cpp =loop.cpp=]): +For example, for a for-loop but same for while- and all other loops (see [@../../example/features/loop.cpp =loop.cpp=]): [import ../example/features/loop.cpp] [loop] -More in general, [funcref boost::contract::function] can be used to program preconditions, postconditions, and exception guarantees of any block of code in a function implementation. -For example (see also [@../../example/features/code_block.cpp =code_block.cpp=]): +More in general, [funcref boost::contract::function] can be used to program preconditions, postconditions, and exception guarantees of any block of code in a given function. +For example (see [@../../example/features/code_block.cpp =code_block.cpp=]): [import ../example/features/code_block.cpp] [code_block] -Finally, at the moment this library does not support contracts for functions declared `constexpr`. +Finally, at the moment this library does not support contracts for functions declared `constexpr` and literal classes. [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 function 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); +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: +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). -Also note that even if supported, contracts for constexpr functions probably would not use old values (because `constexpr` prevents functions from having any side effect visible to the caller and variables recording such side-effects are usually the candidates for old value copies) and subcontracting (because constexpr functions cannot be virtual). +Also note that even if supported, contracts for `constexpr` functions probably would not use old values (because `constexpr` prevents functions from having any side effect visible to the caller and variables recording such side-effects are usually the candidates for old value copies) and subcontracting (because `constexpr` functions cannot be virtual). ] [endsect] @@ -239,33 +258,37 @@ Also note that even if supported, contracts for constexpr functions probably wou [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, for example (see also [@ ../../example/features/check.cpp =check.cpp=]): +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.). +For example (see [@ ../../example/features/check.cpp =check.cpp=]): [import ../example/features/check.cpp] [check_class] -Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove compile-time and run-time overhead of implementation checks when [macroref BOOST_CONTRAT_NO_CHECKS] is defined (see __Disable_Contract_Checking__ and __Disable_Contract_Compilation__ for similar considerations for all other contract conditions supported by this library), for example (see also [@ ../../example/features/check.cpp =check.cpp=]): +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=]): [check_macro] -These implementation checks are essentially equivalent to using the C-style `assert` macro but with the following differences: +(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.) -* A failure of these implementation checks will call [funcref boost::contract::check_failure] (see also [funcref boost::contract::set_check_failure] and [funcref boost::contract::get_check_failure]). -* These implementation checks are automatically disabled when other contract conditions specified using this libraries are being checked already (to avoid infinite recursion). -* These implementation checks are disabled defining [macroref BOOST_CONTRACT_NO_CHECKS] (instead of `NDEBUG` for disabling `assert`). +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`). [endsect] -[section Old Values at Body] +[section Old Copies at Body] -In the examples seen so far old value variables of type [classref boost::contract::old_ptr] are initialized to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] at the point of their declaration. -This is correctly done before the function body is executed but it is also done before the contract is executed, therefore even before class invariants at function entry and preconditions are checked. +In the examples seen so far, old value variables of type [classref boost::contract::old_ptr] are initialized to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] at the point of their declaration. +This is correctly done before the function body is executed but it is also done before the contract is declared, therefore even before class invariants (for public functions) and preconditions are checked at function entry. This might work well in most cases, however in general old values should be copied before executing the function body but after checking entry class invariants and preconditions (see __Assertions__). -There can 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. +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. -For that, this library also allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and to assign them later to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] in a nullary functor [^['h]]`()` passed to `.old(`[^['h]]`)`. -The functor [^['h]]`()` is called by this library before the function body is executed but only after class invariants and preconditions are checked: +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: [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. @@ -292,25 +315,25 @@ Other contract programming frameworks allow to mix this order, that could have b }) ; -For example, the following old value expression `s[index]` passed to [macroref BOOST_CONTRACT_OLDOF] is valid only after the precondition has checked that `index` is within range `index < s.size()`. -Therefore, `old_y` is first declared using its default constructor (i.e., initialized to a null pointer) and later assigned to a copy of `s[index]` in `.old(...)` after the precondition has checked that `index` is in range (see also [@../../example/features/old.cpp =old.cpp=]): +For example, the following old value expression `s[index]` passed to [macroref BOOST_CONTRACT_OLDOF] is valid only after the precondition has checked that `index` is within valid range `index < s.size()`. +Therefore, `old_y` is first declared using its default constructor (i.e., initialized to a null pointer) and later assigned to a copy of `s[index]` in `.old(...)` after the precondition has checked `index` (see [@../../example/features/old.cpp =old.cpp=]): [import ../example/features/old.cpp] [old] -The functor passed to `.old(...)` should capture all variables it needs to evaluate and copy old value expressions. +The functor passed to `.old(...)` should capture all variables it needs to evaluate to copy the old value expressions passed to [macroref BOOST_CONTRACT_OLDOF]. 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 also __Constant_Correctness__). +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.). [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 [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 user-defined function. -This is arguably less correct than calling [funcref boost::contract::old_failure] because an exception thrown by an old value copy causes the program to fail checking its postconditions and exception guarantees but should not automatically causes the enclosing user-defined function to thrown an exception (this might not be a significant difference in practice, or it could be an additional reason to use `.old(...)` instead of copying old values when they are declared before the contract). +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. +This is arguably less correct than calling [funcref boost::contract::old_failure] because an exception thrown by an old value copy causes the program to fail checking its postconditions and exception guarantees but should not automatically causes the enclosing function to thrown an exception (this might not be a significant difference in practice, but it could be an additional reason to use `.old(...)` instead of copying old values when they are declared before the contract). [footnote *Rationale:* -It would be possible to wrap all old value operations ([classref boost::contract::old_ptr] copy constructor, [funcref boost::contract::make_old], etc.) in try-catch statements so this library will call [funcref boost::contract::postcondition_failure] also when old values are copied when they are constructed outside `.old(...)`. -However, that will prevent this library from knowing the [enumref boost::contract::from] parameter which will not be viable (specifically because destructors can have postconditions so that parameter is necessary to make sure user-defined failure handlers can be programmed to never throw from destructors as C++ requires). +It would be possible to wrap all old value operations ([classref boost::contract::old_ptr] copy constructor, [funcref boost::contract::make_old], etc.) in try-catch statements so this library will call [funcref boost::contract::old_failure] also when old values are copied when they are constructed outside `.old(...)`. +However, that will prevent this library from knowing the [enumref boost::contract::from] parameter and that would be problematic (specifically because destructors can have postconditions so that parameter is necessary to make sure user-defined failure handlers can be programmed to never throw from destructors as C++ usually requires). ] ] @@ -322,23 +345,23 @@ The function names passed to [macroref BOOST_CONTRACT_OVERRIDE] and [macroref BO There is a separate macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that can be used to explicitly specify the name of the type that will be passed to [funcref boost::contract::public_function] as a template argument: [footnote *Rationale:* -A different macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] is used instead of overloading [macroref BOOST_CONTRACT_OVERRIDE] using variadic macros because the override macros cannot be programmed manually by the users so making them variadic would prevent to use this library on compilers that do not support variadic macros (see also __No_Macros__). +A different macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] is used instead of overloading [macroref BOOST_CONTRACT_OVERRIDE] using variadic macros because the override macros cannot be programmed manually by users so making it a variadic would prevent to use this library on compilers that do not support variadic macros (see __No_Macros__). ] BOOST_CONTRACT_OVERRIDE(``[^['function-name]]``) // Generate `override_...`. BOOST_CONTRACT_NAMED_OVERRIDE(``[^['type-name]]``, ``[^['function-name]]``) // Generate `type-name`. -For example, the following public function override is named `_1` so `BOOST_CONTRACT_OVERRIDE(_1)` would generate a type named `override__1` (which is reserved in C++ because it contains double underscores `__`), `BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1)` is used to name the type `override1` instead (see also [@../../example/features/named_override.cpp =named_override.cpp=]): +For example, the following public function override is named `_1` so `BOOST_CONTRACT_OVERRIDE(_1)` would generate a type named `override__1` (which is reserved in C++ because it contains double underscores `__`), `BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1)` is used to name the type `override1` instead (see [@../../example/features/named_override.cpp =named_override.cpp=]): [named_override] -The [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macro can also be used when the name `override_`[^['function-name]] generated by [macroref BOOST_CONTRACT_OVERRIDE] would clash with other names in user code, to generate names in CamelCase or in any other style, in any other case when programmers need or want to generate names different from `override_...`. +The [macroref BOOST_CONTRACT_NAMED_OVERRIDE] macro can also be used when the name `override_`[^['function-name]] generated by [macroref BOOST_CONTRACT_OVERRIDE] would clash with other names in user code, to generate names in CamelCase or in any other preferred style, and in any other case when programmers need or prefer to generate names different from `override_...`. Note that there is not a `BOOST_CONTRACT_NAMED_OVERRIDES` macro so [macroref BOOST_CONTRACT_NAMED_OVERRIDE] needs to be invoked separately on each function name (there is instead a [macroref BOOST_CONTRACT_OVERRIDES] macro as seen in __Public_Function_Overrides__). [footnote *Rationale:* -The syntax for invoking a possible `BOOST_CONTRACT_NAMED_OVERRIDES` macro would need to be something like `BOOST_CONTRACT_NAMED_OVERRIDES((`[^['type-name1]]`, `[^['function-name1]]`), (`[^['type-name2]]`, `[^['function-name2]]`), ...)`. -The authors felt this syntax is more cumbersome than repeating single `BOOST_CONTRACT_NAMED_OVERRIDE` invocations `BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name1]]`, `[^['function-name1]]`) BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name2]]`, `[^['function-name2]]`) ...` so decided not to provide the `BOOST_CONTRACT_NAMED_OVERRIDES` macro. +The syntax for invoking a possible `BOOST_CONTRACT_NAMED_OVERRIDES` macro would need to be something like `BOOST_CONTRACT_NAMED_OVERRIDES(`[^['type-name1]]`, `[^['function-name1]]`, `[^['type-name2]]`, `[^['function-name2]]`, ...)`. +The authors felt this syntax is less readable than repeating single `BOOST_CONTRACT_NAMED_OVERRIDE` invocations `BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name1]]`, `[^['function-name1]]`) BOOST_CONTRACT_NAMED_OVERRIDE(`[^['type-name2]]`, `[^['function-name2]]`) ...` so decided not to provide the `BOOST_CONTRACT_NAMED_OVERRIDES` macro. ] [endsect] @@ -347,25 +370,24 @@ The authors felt this syntax is more cumbersome than repeating single `BOOST_CON As we have seen so far, programmers are required to decorate their classes declaring extra members that are internally used by this library to check contracts: -* The `invariant` and `static_invariant` member functions (used to check class invariants, see also __Class_Invariants__). -* The `base_types` member type declared via [macroref BOOST_CONTRACT_BASE_TYPES] (used to implement subcontracting, see also __Public_Function_Overrides__). -* The `override_...` member types declared via [macroref BOOST_CONTRACT_OVERRIDE], [macroref BOOST_CONTRACT_NAMED_OVERRIDE], and [macroref BOOST_CONTRACT_OVERRIDES] (used to implement subcontracting for overriding functions, see also __Public_Function_Overrides__). +* The `invariant` and `static_invariant` member functions (used to check class invariants, see __Class_Invariants__). +* The `base_types` member type declared via [macroref BOOST_CONTRACT_BASE_TYPES] (used to implement subcontracting, see __Public_Function_Overrides__). +* The `override_...` member types declared via [macroref BOOST_CONTRACT_OVERRIDE], [macroref BOOST_CONTRACT_NAMED_OVERRIDE], and [macroref BOOST_CONTRACT_OVERRIDES] (used to implement subcontracting for overriding functions, see __Public_Function_Overrides__). [footnote *Rationale:* -The internals of the `override_...` type generated by [macroref BOOST_CONTRACT_OVERRIDE] use names reserved by this library to users should not actually use such a type even when it is defined `public`. -(On a related note, in theory using C++14 generic lambdas, the [macroref BOOST_CONTRACT_OVERRIDE] macro could be re-implemented in a way so it can be expanded at function scoped, instead of class scoped.) +The internals of the `override_...` type generated by [macroref BOOST_CONTRACT_OVERRIDE] use names reserved by this library so programmers should not actually use such a type even when it is declared `public`. ] -In general, these members must be declared `public` in the user class in order for this library to access them. +In general, these members must be declared `public` in the user class in order for this library to be able to access them. [footnote There is some variability among compiler implementations: -the `base_types` member type needs to be declared `public` on all MSVC, GCC, ang CLang; -the `invariant` and `static_invariant` member functions need to be declared `public` on MSVC, but not on GCC and CLang; -the `override_...` member types do not have to be declared `public` on any compiler. +The `base_types` member type needs to be declared `public` on MSVC, GCC, ang CLang; +The `invariant` and `static_invariant` member functions need to be declared `public` on MSVC, but not on GCC and CLang; +The `override_...` member types do not have to be declared `public` on any compiler. In any case, declaring the [classref boost::contract::access] class `friend` allows to always declare all these extra members `private` on all compilers. ] However, programmers might need to more precisely control the public members of their classes to prevent incorrect access of encapsulated members. -All these members can be declared `private` as long as the [classref boost::contract::access] class is declared as `friend` of the user class, for example (see also [@../../example/features/access.cpp =access.cpp=]): +All these members can be declared `private` as long as the [classref boost::contract::access] class is declared as `friend` of the user class, for example (see [@../../example/features/access.cpp =access.cpp=]): [import ../example/features/access.cpp] [access] @@ -373,45 +395,45 @@ All these members can be declared `private` as long as the [classref boost::cont This technique is not used in most examples of this documentation only for brevity, but programmers are encouraged to use it in real code. [warning -Not declaring this class friend of user-defined classes might cause compiler errors on some compilers (e.g., MSVC) because the private members needed to check the contracts will not be accessible. +Not declaring this class friend of user classes might cause compiler errors on some compilers (e.g., MSVC) because the private members needed to check the contracts will not be accessible. On other compilers (e.g., GCC and CLang), the private access will instead fail SFINAE and no compiler error will be reported while invariants and subcontracting will be silently skipped at run-time. -Therefore, programmers must make sure to either declare invariant functions and base types @c typedef as public members or to declare this class as friend. +Therefore, programmers should always make sure to either declare invariant functions and base types `typedef` as public members or to declare the [classref boost::contract::access] class as friend. ] [endsect] [section Throw on Failure (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 (in fact, [macroref BOOST_CONTRACT_ASSERT] simply expands to code that throws a [classref boost::contract::assertion_failure] exception, see also __No_Macros__), this library will call an appropriate /contract failure handler/ function as follow: +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: -# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from preconditions `.precondition(...)` call [funcref boost::contract::precondition_failure]. -# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from postconditions `.postcondition(...)` call [funcref boost::contract::postcondition_failure]. -# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from exception guarantees `.except(...)` call [funcref boost::contract::except_failure]. -# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from class invariants `invariant()` and `static_invariant()` call [funcref boost::contract::entry_invariant_failure] when checked at function entry and [funcref boost::contract::exit_invariant_failure] when checked at function exit. -# Exceptions thrown from old value copies at body `.old(...)` call [funcref boost::contract::old_failure]. -# False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from implementation checks `boost::contract::check c = `[^['nullary-functor]] and [macroref BOOST_CONTRACT_CHECK] call [funcref boost::contract::check_failure]. +* Preconditions: False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from within `.precondition(...)` call [funcref boost::contract::precondition_failure]. +* Postconditions: False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from within `.postcondition(...)` call [funcref boost::contract::postcondition_failure]. +* Exceptions guarantees: False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from within `.except(...)` call [funcref boost::contract::except_failure]. +* Class invariants: False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from `invariant()` and `static_invariant()` call [funcref boost::contract::entry_invariant_failure] when checked at function entry and [funcref boost::contract::exit_invariant_failure] when checked at function exit. +* Old copies at body: Exceptions thrown from old value copies at body within `.old(...)` call [funcref boost::contract::old_failure]. +* Implementation checks: False [macroref BOOST_CONTRACT_ASSERT] assertions and exceptions thrown from implementation checks `boost::contract::check c = `[^['nullary-functor]] and [macroref BOOST_CONTRACT_CHECK] calls [funcref boost::contract::check_failure]. By default, these contract failure handlers print a message to the standard error `std::cerr` and then terminate the program calling `std::terminate`. [footnote *Rationale:* In general, when a contract fails the only safe thing to do is to terminate program execution (because the contract failure indicates a bug in the program, and in general the program is in a state for which no operation can be successfully performed, so the program should be stopped). Therefore, this library terminates the program by default. -However, for specific applications, programmers could implement some fail-safe mechanism for which some mission-critical operation can always be performed upon handling failures so this library allows programmers to override the default contract failure handlers to fully customize how to handle contract failures. +However, for specific applications, programmers could implement some fail-safe mechanism for which some mission-critical operation could always be performed upon handling failures so this library allows programmers to override the default contract failure handlers to fully customize how to handle contract failures. ] However, programmers can override the default contract failure handlers to perform any custom action on contract failure using the following functions respectively: -# [funcref boost::contract::set_precondition_failure] -# [funcref boost::contract::set_postcondition_failure] -# [funcref boost::contract::set_except_failure] -# [funcref boost::contract::set_entry_invariant_failure] and [funcref boost::contract::set_exit_invariant_failure], or [funcref boost::contract::set_invariant_failure] (to set both entry and exit invariant failure handlers at once for convenience) -# [funcref boost::contract::set_old_failure] -# [funcref boost::contract::set_check_failure] +* Preconditions: [funcref boost::contract::set_precondition_failure]. +* Postconditions: [funcref boost::contract::set_postcondition_failure]. +* Exception guarantees: [funcref boost::contract::set_except_failure]. +* Class invariants: [funcref boost::contract::set_entry_invariant_failure] and [funcref boost::contract::set_exit_invariant_failure], or [funcref boost::contract::set_invariant_failure] (to set both entry and exit invariant failure handlers at once for convenience). +* Old copies at body: [funcref boost::contract::set_old_failure]. +* Implementation checks: [funcref boost::contract::set_check_failure]. -These `set_..._failure(`[^['f]]`)` function calls return the contract failure handler functor [^['f]] that they take as input parameter, for example (see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): +These `set_..._failure(`[^['f]]`)` function calls return the contract failure handler functor [^['f]] that they take as input parameter, for example (see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): [footnote *Rationale:* Even if somewhat different from `std::set_terminate`, the `set_..._failure` functions take a functor as parameter (so to handle not just function pointers, but also lambdas, binds, etc.) and return this same functor as result (so they can be concatenated). -The related `get_..._failure` functions can be used to query the functors currently set for each contract. +The related `get_..._failure` functions can be used to query the functors currently set as failure handlers. ] [import ../example/features/throw_on_failure.cpp] @@ -420,33 +442,33 @@ The related `get_..._failure` functions can be used to query the functors curren When programming custom failure handlers that trow exceptions instead of terminating the program, programmers should be wary of the following: * In order to comply with C++ and STL exception safety, destructors should never throw. -This library passes a [classref boost::contract::from] parameter to the contract failure handlers for preconditions ([funcref boost::contract::precondition_failure]), postconditions ([funcref boost::contract::postcondition_failure]), class invariants ([funcref boost::contract::entry_invariant_failure] and [funcref boost::contract::exit_invariant_failure]), and old value copies at body ([funcref boost::contract::old_failure]). -This [classref boost::contract::from] parameter indicates if the contract failure occurred in a destructor, constructor, or function call so programmers can use it code custom contract failure hander functions that never throw from destructors (in the example above, contract failures from destructors are simply ignored even if that is probably never a safe thing to do in real code). -* C++ stack-unwinding will executed base class destructors even when the derived class destructor trows an exception. -Therefore, the contracts of base class destructors will continue to be checked when contract failure handlers are programmed to throw exceptions on contract failures from destructors. -* Implementation checks can appear in any code, including destructor implementation code, so [funcref boost::contract::check_failure] should also never throw, or implementation checks should never be used in destructors. -* The contract failure handler for exception guarantees [funcref boost::contract::except_failure] should also never throw (regardless of its [classref boost::contract::from] parameter). -That is because when [funcref boost::contract::except_failure] is called there is already an active exception on the stack, the exception that triggered the exception guarantees to be checked in the first place (throwing an exception while there is already an active exception will force C++ to terminate the program). +This library passes a [enumref boost::contract::from] parameter to the contract failure handlers for preconditions ([funcref boost::contract::precondition_failure]), postconditions ([funcref boost::contract::postcondition_failure]), class invariants ([funcref boost::contract::entry_invariant_failure] and [funcref boost::contract::exit_invariant_failure]), and old value copies at body ([funcref boost::contract::old_failure]). +This [enumref boost::contract::from] parameter indicates if the contract failure occurred in a destructor, constructor, or function call so programmers can use it to code custom contract failure hander functions that never throw from destructors. +(In the example above, contract failures from destructors are simply ignored even if that is probably never a safe thing to do in real code.) +* C++ stack-unwinding will execute base class destructors even when the derived class destructor trows an exception. +Therefore, the contracts of base class destructors will continue to be checked when contract failure handlers are programmed to throw exceptions on contract failures from destructors (yet another reason to not throw exception from destructors, not even for contract failures). +* Implementation checks can appear in any code, including destructor implementation code, so [funcref boost::contract::check_failure] should also never throw, or implementation checks should never be used in destructors (note that [funcref boost::contract::check_failure] does not provide the [enumref boost::contract::from] parameter so it is not possible to differentiate from implementation checks failing from destructors instead than from other parts of the code). +* The contract failure handler for exception guarantees [funcref boost::contract::except_failure] should also never throw (regardless of the value of its [enumref boost::contract::from] parameter) because when [funcref boost::contract::except_failure] is called there is already an active exception on the stack, the exception that triggered the exception guarantees to be checked in the first place (and throwing an exception while there is already an active exception will force C++ to terminate the program or lead to undefined behaviour). [note It is the responsibility of the programmers to decide how to handle contract failures from destructors when they program custom contract failure handlers that throw exceptions instead of terminating the program (given that C++ and STL exception safety rules requires destructors to never throw). -This is not a simple dilemma and it might be one more reason to terminate the program instead of throwing exceptions when assertions fail in C++ (as this library and also the C-style `assert` do by default). +This is not a simple dilemma and it might be a good reason to terminate the program instead of throwing exceptions when assertions fail in C++ (as this library and also C-style `assert` do by default). ] -Contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using [macroref BOOST_CONTRACT_ASSERT]`(`[^['condition]]`)` as we have seen so far (see also __No_Macros__). +Contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using [macroref BOOST_CONTRACT_ASSERT]`(`[^['condition]]`)` as we have seen so far (see __No_Macros__). Alternatively, contract assertions can be programmed to throw any other exception (including user-defined exceptions) using code similar to the following: if(!``[^['condition]]``) throw ``[^['exception-object]]``; -For example, if the following precondition functor throws the user-defined exception `too_large_error` then the contract failure handler [funcref boost::contract::precondition_failure] will be called (same as when preconditions programmed using [macroref BOOST_CONTRACT_ASSERT] fails, see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): +For example, if the following precondition functor throws the user-defined exception `too_large_error` then the contract failure handler [funcref boost::contract::precondition_failure] will be called (same as when preconditions programmed using [macroref BOOST_CONTRACT_ASSERT] fail, see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): [throw_on_failure_class_begin] [throw_on_failure_ctor] [throw_on_failure_class_end] -Finally, note that the exception specifiers `noexcept` (since C++11) and `throw` (deprecated in C++11) of the enclosing operation declaring the contract correctly apply to the contract code itself. -Therefore, even if the contract failure handlers are reprogrammed to throw exceptions in case of contract failures, such exception will never be thrown outside the context of the enclosing operation if that is not in accordance with the exception specifiers of such operation (notably all destructors are implicitly declared `noexcept(true)` in C++11). -For example, the following code will never throw from the destructor, not even if the class invariants checked at destructor entry throw `too_large_error` and the contract failure handlers for invariants are programmed to throw from destructors as well (the program will always terminate in this case instead, see also [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): +Finally, note that the exception specifiers `noexcept` (since C++11) and `throw` (deprecated in C++11) of the enclosing operation declaring the contract correctly apply to the contract code as well. +Therefore, even if the contract failure handlers are reprogrammed to throw exceptions in case of contract failures, those exceptions will never be thrown outside the context of the enclosing operation if that is not in accordance with the exception specifiers of that operation (e.g., note that all destructors are implicitly declared `noexcept` in C++11). +For example, the following code will correctly never throw from the `noexcept` destructor, not even if the class invariants checked at destructor entry throw `too_large_error` and the contract failure handlers for invariants are programmed to throw from destructors (the program will always terminate in this case instead, see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): [throw_on_failure_class_begin] [throw_on_failure_dtor] diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk index 7dfc809..19425f9 100644 --- a/doc/contract_programming_overview.qbk +++ b/doc/contract_programming_overview.qbk @@ -9,13 +9,13 @@ [:['["It is absurd to make elaborate security checks on debugging runs, when no trust is put in the results, and then remove them in production runs, when an erroneous result could be expensive or disastrous. What would we think of a sailing enthusiast who wears his life-jacket when training on dry land but takes it off as soon as he goes to sea?]]] [:['-- Charles Antony Richard Hoare (see __Hoare73__)]] -This section gives an overview of Contract Programming (see __Meyer97__, __Mitchell02__, and __N1613__ for a more detailed introduction to Contract Programming). -Readers that already have a basic understanding of Contract Programming can skip this section and come back to it after reading the __Tutorial__. +This section gives an overview of Contract Programming (see __Meyer97__, __Mitchell02__, and __N1613__ for more detailed introductions to Contract Programming). +Readers that already have a basic understanding of Contract Programming can skip this section and maybe come back to it after reading the __Tutorial__. [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 to code program specifications. -Then, this library aims to be the best and more complete Contract Programming library for C++ (and that does not use preprocessing and other tools external to the C++ language itself). +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). ] [section Assertions] @@ -24,10 +24,10 @@ 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 with operations that have preconditions which are often referred to as having a /narrow contract/ (note that an operation with truly narrow contracts should not 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 should not even 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..." just for a matter of clarity and style. +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...". ] * /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. @@ -35,38 +35,36 @@ Postconditions can access the function return value (for non-void functions) and Exceptions specifications can access old values (but not the function return value). [footnote *Rationale:* -Exception (safety) guarantees have long been part of C++ documentation, but they were first introduced by this library as formal assertions to be checked as part of contracts. -Checking of exception specification assertions is not part of __N1962__ or other references listed in the __Bibliography__. +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 public non-static member function (even if they throw exceptions), before the destructor is executed and if the destructor throws an exception (e.g, class invariants can define valid states for all objects of a given class). -It is possible to specify a different set of class invariants for volatile member 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 member function (even if static). +* /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/. +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:* -Static and volatile class invariants were first introduced by this library to reflect the fact that C++ supports both static and volatile member functions. +Static and volatile class invariants were first introduced by this library to reflect the fact that C++ supports both static and volatile public functions. Static and volatile class invariants are not part of __N1962__ or other references listed in the __Bibliography__. ] -Arguably, class invariants can 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 a class. -Class invariants can also be used to specify /basic/ exception safety guarantees for an object (because they are checked at exit of public member function even when those throw an exception), while exception guarantees assertions can be used to specify /strong/ exception safety for given operations on the same object. * /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__). -Furthermore, it is 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). +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. + +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). [note -This library implements this requirement but it should be noted that, in order to globally disable assertions while checking another assertion, some kind of global arbitrating variable needs to be used by the library implementation. +This library implements this requirement but in order to globally disable assertions while checking another assertion some kind of global arbitrating variable needs to be used by this library implementation. This library will automatically protect such a global variable from race conditions in multi-threated programs, but this will effectively introduce a global lock in the program (the [macroref BOOST_CONTRACT_DISABLE_THREADS] macro can be defined to disable this global lock but at the risk of incurring in race conditions). +[footnote *Rationale:* -[macroref BOOST_CONTRACT_DISABLE_THREADS] is named similarly to `BOOST_DISABLE_THREADS`. +[macroref BOOST_CONTRACT_DISABLE_THREADS] is named after `BOOST_DISABLE_THREADS`. +] ] 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. -Of course, not all formal contract assertions can actually be programmed 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. -However, in case the iterator range is invalid, such a code would render undefined behaviour or run forever instead of failing an assertion. -Nevertheless, a large amount of contract conditions can be successfully programmed in C++ as illustrated by the numerous examples in this documentation and from the literature (see also __Examples__ and __Bibliography__). - +[heading C-Style Assertions] 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: @@ -74,11 +72,11 @@ Using `assert` is common practice for many programmers but it suffers of the fol * `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). 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 (e.g., extra member functions and try blocks). +* `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. +* `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). -Contract Programming does not suffers of these limitations instead. +Contract Programming does not suffers of these limitations. [endsect] @@ -98,8 +96,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 member 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 Programing 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. * 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. @@ -117,8 +116,7 @@ However, the probability that programmers make a mistake twice (in both the body ] * Easier testing: Contract Programming facilitates testing because a contract naturally specifies what a test should check. -For example, preconditions of a function state which inputs cause the function to fail and postconditions state which outputs are produced by the function on successful exit. -(That said, Contract Programming should be seen as a tool to complement, but obviously not to replace, testing.) +For example, preconditions of a function state which inputs cause the function to fail and postconditions state which outputs are produced by the function on successful exit (Contract Programming should be seen as a tool to complement, but obviously not to replace, testing). * Formal design: Contract Programming can serve to reduce the gap between designers and programmers by providing a precise and unambiguous specification language in terms of the contract assertions. Moreover, contracts can make code reviews easier by clarifying some of the semantics and usage of the code. @@ -128,34 +126,39 @@ This keeps the base class programmers in control as overriding functions always * 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. +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. +However, in case the iterator range is invalid, such a code would render undefined behaviour or run forever instead of failing an assertion. +Nevertheless, a large amount of contract assertions can be successfully programmed in C++ as illustrated by the numerous examples in this documentation and from the literature (for example see how much of STL [link N1962_vector_anchor `vector`] contract assertions can actually be programmed in C++ using this library). + [heading Costs] In general, Contract Programming benefits come at the cost of performance as discussed in detail by both __Stroustrup94__ and __Meyer97__. -However, while performance trade-offs should be carefully considered depending on the specific application domain, software quality cannot be sacrificed: It is difficult to see value in software that quickly and efficiently provides incorrect results. +While performance trade-offs should be carefully considered depending on the specific application domain, software quality cannot be sacrificed: It is difficult to see value in software that quickly and efficiently provides incorrect results. The run-time performances are negatively impacted by Contract Programming mainly because of extra time require to: * Check the asserted conditions. -* Copy old and return values when these are used in postconditions. -* Call additional functions that specify preconditions, postconditions, exception guarantees, class invariants, etc. (especially for subcontracting): +* Copy old values when these are used in postconditions and exception guarantees. +* Call additional functors that check preconditions, postconditions, exception guarantees, class invariants, etc. (especially for subcontracting). [note -In general, contracts introduce at least three extra (functor) calls to check preconditions, postconditions, and exception guarantees for any given non-member function call. -Public member functions introduce also two more (function) calls to check class invariants (at entry and at exit). +In general, contracts introduce at least three extra functor calls to check preconditions, postconditions, and exception guarantees for any given non-member function call. +Public functions introduce also two more function calls to check class invariants (at entry and at exit). For subcontracting, these extra calls (some of which become virtual calls) are repeated for the number of functions being overridden from the base classes (possibly deep in the inheritance tree). -In addition to that, this library introduces a number of internal calls to its implementation in order to properly check the contracts. +In addition to that, this library introduces a number of function calls internal to its implementation in order to properly check the contracts. ] To mitigate the run-time performance impact, programmers can selectively disable run-time checking of some of the contract assertions. -Programmers will have to decide based on the performance trade-offs required by their applications, but a reasonable approach often is to: +Programmers will have to decide based on the performance trade-offs required by their applications, but a reasonable approach often is to (see __Disable_Contract_Checking__): * Always write contracts to clarify the semantics of the design embedding the specifications directly in the code and making the code self-documenting. -* Enable preconditions, postconditions, and class invariants checking during initial testing. -* Enable only preconditions (and possibly class invariants, but not postconditions and exception guarantees) checking during release testing and for the final release (see __Disable_Contract_Checking__). +* 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. -This approach is usually reasonable because in well-tested production code, validating the function body implementation using postconditions (and possibly class invariants) is rarely needed since the function has shown itself to be ["correct] during testing. +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 even class invariants. [endsect] @@ -163,78 +166,80 @@ Furthermore, postconditions and also exception guarantees (with related old valu [heading Non-Member Functions] -A call to a non-member function with a contract executes the following steps (see also [funcref boost::contract::function]): +A call to a non-member function with a contract executes the following steps (see [funcref boost::contract::function]): # Check function preconditions. # Execute the function body. # If the body did not throw an exception, check function postconditions. # Else, check function exception guarantees. -[heading Private and Protected Member Functions] +[heading Private and Protected Functions] -In Contract Programming, Private and protected member functions do not have to satisfy the class invariants (because these functions are considered part of the implementation of the class). -Furthermore, the __substitution_principle__ does not apply to private and protected member functions (because these functions are not accessible to the user at the calling site where the __substitution_principle__ applies). +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. +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 member functions with contracts execute the same steps as the ones indicated for non-member functions above (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, but without checking class invariants and without subcontracting). [endsect] [section Public Function Calls] -[heading Overriding Public Member Functions] +[heading Overriding Public Functions] -Let's consider a public member 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). -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. +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). +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.). In case of multiple inheritance this search also extends widely to all multiple public base classes following their order of declaration in the derived class inheritance list (as usual in C++, this search could result in multiple overridden functions and therefore in subcontracting from multiple public base classes). -Note that only public base classes are considered for subcontracting (because private and protected base classes are not accessible to the user at the calling site where the __substitution_principle__ applies). +Note that only public base classes are considered for subcontracting because private and protected base classes are not accessible to the user at the calling site where the __substitution_principle__ applies. -A call to the overriding public member function with a contract executes the following steps (see also [funcref boost::contract::public_function]): +A call to the overriding public function with a contract executes the following steps (see [funcref boost::contract::public_function]): # Check static class invariants __AND__ non-static class invariants for all overridden bases, __AND__ then check the derived class static __AND__ non-static invariants. -# Check preconditions of overridden public member functions from all overridden bases in __OR__ with each other, __OR__ else check the overriding function preconditions in the derived class. +# Check preconditions of overridden public functions from all overridden bases in __OR__ with each other, __OR__ else check the overriding function preconditions in the derived class. # Execute the overriding function body. # Check static class invariants __AND__ non-static class invariants for all overridden bases, __AND__ then check the derived class static __AND__ non-static invariants (even if the body threw an exception). -# If the body did not throw an exception, check postconditions of overridden public member 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 member functions from all overridden bases in __AND__ with each other, __AND__ then check the overriding function exception guarantees in the derived class. +# 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 member functions check static class invariants __AND__ /volatile/ class invariants instead. -Preconditions and postconditions of volatile member functions and volatile class invariants access the object as `volatile`. +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. [note [#and_anchor] [#or_anchor] In this documentation __AND__ and __OR__ indicate the logic /and/ and /or/ operations evaluated in /short-circuit/. For example: `p` __AND__ `q` is true if and only if both `p` and `q` are true, but `q` is never evaluated when `p` is false; `p` __OR__ `q` is true if and only if either `p` or `q` are true, but `q` is never evaluated when `p` is true. + +As indicated by the steps above and in accordance with the __substitution_principle__, subcontracting checks preconditions in __OR__ while class invariants, postconditions, and exceptions guarantees in __AND__ with preconditions, class invariants, postconditions, and exceptions guarantees of base classes. ] -Class invariants are checked before preconditions and postconditions so the programming of 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 the programming of derived class contract assertions can be simplified by assuming that public base class contracts are satisfied already. +[heading Non-Overriding Public Functions] -[heading Non-Overriding Public Member Functions] - -A call to a public non-static member function with a contract (that is not overriding functions from any of the public base classes) executes the following steps (see also [funcref boost::contract::public_function]): +A call to a non-static public function with a contract (that does not override functions from any of the public base classes) executes the following steps (see [funcref boost::contract::public_function]): # Check class static __AND__ non-static invariants (but none of the invariants from base classes). # Check function preconditions (but none of the preconditions from functions in base classes). -# Executed the function body. +# Execute the function body. # Check the class static __AND__ non-static invariants (even if the body threw an exception, but none of the invariants from base classes). # 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 member functions check static class invariants __AND__ /volatile/ class invariants instead. -Preconditions and postconditions of volatile member functions and volatile class invariants access the object as `volatile`. +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. -However, none of the contracts of the base classes are checked because this function is not overriding functions from any of the public base classes (so the __substitution_principle__ does not require non-overriding functions to subcontract). +However, none of the contracts of the base classes are checked because this function does not override any functions from any of the public base classes (so the __substitution_principle__ does not require to subcontract in this case). -[heading Static Public Member Functions] +[heading Static Public Functions] -A call to a public static member function with a contract executes the following steps (see also [funcref boost::contract::public_function]): +A call to a static public function with a contract executes the following steps (see [funcref boost::contract::public_function]): # Check static class invariants (but not the non-static invariants and none of the invariants from base classes). # Check function preconditions (but none of the preconditions from function in base classes). -# Executed the function body. +# Execute the function body. # Check static class invariants (even if the body threw an exception, but not the non-static invariants and none of the invariants from base classes). # 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). @@ -242,13 +247,13 @@ A call to a public static member function with a contract executes the following Class invariants are checked because this function is part of the class public interface, but only static class invariants can be checked (because this is a static function so it cannot access the object that would instead be required to check non-static class invariants, volatile or not). Furthermore, static functions cannot override any function so the __substitution_principle__ does not apply and they do not subcontract. -Preconditions and postconditions of static member functions and static class invariants cannot access the object (because they are checked by `static` members). +Preconditions and postconditions of static functions and static class invariants cannot access the object (because they are checked from `static` member functions). [endsect] [section Constructor Calls] -A call to a constructor with a contract executes the following steps (see also [classref boost::contract::constructor_precondition] and [funcref boost::contract::constructor]): +A call to a constructor with a contract executes the following steps (see [classref boost::contract::constructor_precondition] and [funcref boost::contract::constructor]): # Check constructor preconditions (but these cannot access the object because the object is not constructed yet). # Execute the constructor member initialization list (if present). @@ -258,10 +263,10 @@ A call to a constructor with a contract executes the following steps (see also [ # Check static class invariants (even if the body threw an exception). # If the body did not throw an exception: # Check non-static __AND__ volatile class invariants (because the object is now successfully constructed). - # Check constructor postconditions (but these cannot access the object old value [^['old]]`(this)` because there was no object before the execution of the constructor body). -# Else, check constructor exception guarantees (but these cannot access the object old value [^['old]]`(this)` because there was no object before the execution of the constructor body, plus they can only access class static members because the object was not successfully constructed upon the constructor body throwing an exception). + # Check constructor postconditions (but these cannot access the object old value [^['oldof]]`(*this)` because there was no object before the execution of the constructor body). +# Else, check constructor exception guarantees (but these cannot access the object old value [^['oldof]]`(*this)` because there was no object before the execution of the constructor body, plus they can only access class static members because the object was not successfully constructed upon the constructor body throwing an exception). -Constructor preconditions are checked before executing the member initialization list so the programming of these initializations can be simplified assuming the constructor preconditions are satisfied (e.g., constructor arguments can be validated by the constructor preconditions before they are used to initialize bases and data members). +Constructor preconditions are checked before executing the member initialization list so programming these initializations can be simplified assuming the constructor preconditions are satisfied (e.g., constructor arguments can be validated by the constructor preconditions before they are used to initialize base classes and data members). As indicated in step 2.a. above, C++ object construction mechanism will automatically check base class contracts when these bases are initialized (no explicit subcontracting behaviour is required here). @@ -269,29 +274,28 @@ As indicated in step 2.a. above, C++ object construction mechanism will automati [section Destructor Calls] -A call to a destructor with a contract executes the following steps (see also [funcref boost::contract::destructor]): +A call to a destructor with a contract executes the following steps (see [funcref boost::contract::destructor]): # Check static class invariants __AND__ non-static __AND__ volatile class invariants. # Execute the destructor body (destructors have no parameters and they can be called at any time after object construction so they have no preconditions). # Check static class invariants (even if the body threw an exception). # If the body did not throw an exception: - # Check destructor postconditions (but these can only access class static members because there is no object after successful execution of the destructor body). + # Check destructor postconditions (but these can only access class static members and the object old value [^['oldof]]`(*this)` because there is no object after successful execution of the destructor body). [footnote *Rationale:* Postconditions for destructors are not part of __N1962__ or other references listed in the __Bibliography__ (but with respect to __Meyer97__ it should be noted that Eiffel does not support static data members and that might by why destructors do not have postconditions in Eiffel). -However, in principle there could be uses for destructor postconditions (e.g., a class that counts object instances could use destructor postconditions to assert that an instance counter stored in a static data member is decreased by `1` because the object has been destructed) so this library supports postconditions for destructors. -Of course, after destructor body execution there is no object anymore so destructor postconditions can only access the static members of the class. +However, in principle there could be uses for destructor postconditions so this library supports postconditions for destructors (e.g., a class that counts object instances could use destructor postconditions to assert that an instance counter stored in a static data member is decreased by `1` because the object has been destructed). ] # Destroy any base class (public or not) according with C++ destruction mechanism and also check the contracts of these base destructors (according with steps similar to the ones listed here). -# Else: +# Else (even if destructors should rarely, if ever, be allowed to throw exceptions in C++): # Check non-static class invariants (because the object was not successfully destructed so it still exists and should satisfy its invariants). - # Check destructor exception guarantees (even if destructors should never be programmed to throw in C++). + # Check destructor exception guarantees. As indicated in step 4.b. above, C++ object destruction mechanism will automatically check base class contracts when the destructor exits without throwing an exception (no explicit subcontracting behaviour is required here). [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 never throw. +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). ] [endsect] @@ -301,18 +305,17 @@ However, in order to comply with STL exception safety guarantees and good C++ pr 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.). -[important 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). -Ultimately, it is the responsibility of the programmers to code assertions that only check and do not change program variables. +[important +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. ] ] -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). - [endsect] [section Specification vs. Implementation] @@ -322,45 +325,45 @@ Therefore, contracts should ideally be programmed within C++ declarations, and n 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 applications were this requirement is truly important). +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). 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 member 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). +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:* -In theory, 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 (but still at the expense of programmers writing extra boiler-plate code). +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++). ] [endsect] [section On Contract Failure] -If precondition, postcondition, 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 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/. 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_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_Failure__). [footnote *Rationale:* -This customizable failure handling mechanism is similar to the one used by `std::terminate` and also proposed by __N1962__. +This customizable failure handling mechanism is similar to the one used by C++ `std::terminate` and also to the one proposed in __N1962__. ] [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 specification 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 specification assertions to be checked in the first place), and this will force C++ to terminate the program. +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. ] -Therefore, it is recommended to terminate the program at least for contract failures from destructors and because when checking exception guarantees (if not in all other cases of contract failures as it is done by default by this library). -This library contract failure handlers report information about the failure that allow programmers to granularly distinguish all these cases and therefore decide when it is appropriate to terminate, trow, or take some other user-specific action depending on the application domain. +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). +The contract failure handler functions programmed using this library have information about the failed contract (preconditions, postconditions, etc.) and the operation that was checking the contract (constructor, destructor, etc.) so programmers can granularly distinguish all cases and decide when it is appropriate to terminate, throw, or take some other user-specific action. [endsect] [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, the __N1962__ proposal (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 __P0186__ (which unfortunately only supports preconditions and postconditions, but does not support class invariants, subcontracting, and not even old values for postconditions), 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 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: [table [ @@ -374,84 +377,76 @@ The following table compares Contract Programming features among this library, t [['Keywords and specifiers]] [ Specifiers: `precondition`, `postcondition`, `invariant`, `static_invariant`, and `base_types`. - -The last three specifiers appear in user code so their names can be changed using [macroref BOOST_CONTRACT_INVARIANT], [macroref BOOST_CONTRACT_STATIC_INVARIANT], and [macroref BOOST_CONTRACT_BASE_TYPEDEF] macros respectively to avoid name clashes. +The last three specifiers appear in user code so their names can be referred to or changed using [macroref BOOST_CONTRACT_INVARIANT], [macroref BOOST_CONTRACT_STATIC_INVARIANT], and [macroref BOOST_CONTRACT_BASES_TYPEDEF] macros respectively to avoid name clashes. ] [Keywords: `precondition`, `postcondition`, `oldof`, and `invariant`.] - [Attributes: `[[requires]]`, `[[ensures]]`.] + [Attributes: `[[expects]]` and `[[ensures]]`.] [Keywords: =require=, =require else=, =ensure=, =ensure then=, =old=, =result=, =do=, and =invariant=.] [Keywords: =in=, =out=, =assert=, and =invariant=.] ][ [['On contract failure]] [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::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]] [Yes, captured by or passed as a parameter to (for virtual functions) the postcondition functor.] [Yes, `postcondition(`[^['result-variable-name]]`)`.] - [No.] + [Yes, `[[ensures `[^['result-variable-name]]`: ...]]`.] [Yes, =result= keyword.] [No.] ][ [['Old values in postconditions]] [ -Yes, [macroref BOOST_CONTRACT_OLD] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old` is used). - -For templates, [classref boost::contract::old_ptr_if_copyable] allows to skip for non-copyable types and [classref boost::contract::condition_if] allows to skip selectively based on old expression type requirements. +Yes, [macroref BOOST_CONTRACT_OLD] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old(...)` is used as shown in __Old_Values_at_Body__). +For templates, [classref boost::contract::old_ptr_if_copyable] skips old value copies for non-copyable types and [classref boost::contract::condition_if] skips old value copies selectively based on old expression type requirements. ] [ Yes, `oldof` keyword (copied after preconditions and before body). - -Never skipped (not even in templates for non-copyable types). +(Never skipped, not even in templates for non-copyable types.) ] [No.] [ Yes, =old= keyword (copied after preconditions and before body). - -Never skipped (but all types are copyable in Eiffel). +(Never skipped, but all types are copyable in Eiffel.) ] [No.] ][ [['Class invariants]] [ -Checked at constructor exit, at destructor entry and throw, and at public member function entry, exit, and throw. - +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 member function. +Static class invariants checked at entry and exit of constructor, destructor, and any (also `static`) public function. ] [ -Checked at constructor exit, at destructor entry and throw, and at public member function entry, exit, and throw. - -Volatile and static class invariants not supported. +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 member functions. - +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 member functions. - -Volatile and static class invariants not supported (`volatile` was deprecated all together in D). +Checked at constructor exit, at destructor entry, and around public functions. +(Volatile and static class invariants not supported, `volatile` was deprecated all together in D.) ] ][ [['Subcontracting]] [ -Yes, also support subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used when declaring base classes, overriding and virtual public member 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, overriding and virtual public functions respectively). ] [ -Yes, also support subcontracting for multiple inheritance but only preconditions only in base classes. +Yes, also supports subcontracting for multiple inheritance but only preconditions only in base classes. [footnote *Rationale:* -The authors of __N1962__ decided to forbid derived classes from subcontracting preconditions because they found such a feature 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 function in __OR__ (so even in __N1962__ preconditions can indirectly be subcontracted by the derived class when multiple inheritance is used). +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]). +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 alway avoid using such a feature if they have no need for it). -(This is essentially the only feature on which this library deliberately differ from __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__.) ] ] [No.] @@ -468,26 +463,26 @@ Furthermore, subcontracting preconditions is soundly defined by the __substituti [['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.] - [Yes.] + [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, see __No_Lambda_Functions__).] + [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.] - [No.] [Yes.] [No.] ][ [['Contracts in specifications or implementation]] - [Implementation (unless manually writing an extra function per contract).] + [Implementation (unless programmers manually write an extra function for any given function).] [Specification (function declaration).] [Specification (function declaration).] [Specification.] [Specification.] ][ [['Function code ordering]] - [Preconditions, postconditions, body.] + [Preconditions, postconditions, exception guarantees, body.] [Preconditions, postconditions, body.] [Preconditions, postconditions, body.] [Preconditions, body, postconditions.] @@ -495,7 +490,7 @@ Furthermore, subcontracting preconditions is soundly defined by the __substituti ][ [['Disable assertion checking within assertions checking (to avoid infinite recursion when checking contracts)]] [ -Yes, but use [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] to disable no assertion while checking preconditions (see also [macroref BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION]). +Yes, but use [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] to disable no assertion while checking preconditions (see [macroref BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION]). [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]). @@ -503,7 +498,7 @@ 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. ] -(In multi-threaded programs this introduces a global lock, see also the [macroref BOOST_CONTRACT_DISABLE_THREADS] macro.) +(In multi-threaded programs this introduces a global lock, see [macroref BOOST_CONTRACT_DISABLE_THREADS].) ] [Yes for class invariants and postconditions, but preconditions disable no assertion.] [No.] @@ -528,16 +523,16 @@ Therefore, this feature was removed in the current revision of this library. ][ [['Disable contract checking]] [ -Yes, contract checking can be skipped at run-time by defining combinations of the [macroref BOOST_CONTRACT_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_INVARIANTS], [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS], and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] macros (completely removing contract code from compiled object code is possible but requires using macro API, see __Disable_Contract_Compilation__.) +Yes, contract checking can be skipped at run-time by defining combinations of the [macroref BOOST_CONTRACT_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_INVARIANTS], [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS], and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] macros (completely removing contract code from compiled object code is possible but requires using macros introduced in __Disable_Contract_Compilation__). ] - [Yes (contract code also removed from compiled object code, but details compiler implementation specific).] - [Yes (contract code also removed from compiled object code, but details compiler implementation specific).] + [Yes (contract code also removed from compiled object code, but details are compiler-implementation specific).] + [Yes (contract code also removed from compiled object code, but details are compiler-implementation specific).] [Yes, but only predefined combinations of preconditions, postconditions, and class invariants can be disabled (contract code also removed from compiled object code).] [Yes.] ][ [['Assertion levels]] [ -Yes, programmers can define their own assertion levels as needed (including "audit" and "axiom", see __Disable_Contract_Checking__). +Yes, programmers can define their own assertion levels as needed (including "audit" and "axiom" as shown in __Disable_Contract_Checking__). ] [No (but a previous revision of this proposal considered adding assertion levels called "assertion ordering").] [Yes, predefined "audit" and "axiom".] @@ -546,7 +541,7 @@ Yes, programmers can define their own assertion levels as needed (including "aud ] ] -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 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 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): [table [ [Reference] [Language] [Notes] ] @@ -560,14 +555,14 @@ This supports class invariants and old values but it does not support subcontrac Interestingly, these contract macros automatically generate Doxygen documentation [footnote *Rationale:* -Older versions of this library used to automatically generate 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, 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. +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. ] 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 the attempt to support subcontracting.) +(The authors have found this work very inspiring when developing initial revisions of this library especially for its attempt to support subcontracting.) ] ] [ [__C2__] [C++] [ This uses an external preprocessing tool (the authors could no longer find this project's code to evaluate it). @@ -592,16 +587,17 @@ 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++: +To the best knowledge of the authors, this the only library that fully supports all Contract Programming features for C++. +Generally speaking: -* Generally speaking, implementing preconditions and postconditions in C++ is not difficult (e.g., using some kind of RAII object). +* 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: `` void fswap(file& x, file& y) - [[requires: x.closed()]] - [[requires: y.closed()]] + [[expects: x.closed()]] + [[excepts: y.closed()]] // Postconditions in function definition below to emulate old values. { file old_x = x; // Emulate old values with local copies (not disabled). @@ -649,11 +645,11 @@ For example, the following possible emulation of class invariants based on __P03 { ... } ~vector() noexcept - [[requires: invariant()]] // ...destructor entry. + [[expects: invariant()]] // ...destructor entry. { ... } void push_back(T const& value) - [[requires: invariant()]] // ...public function entry. + [[expects: invariant()]] // ...public function entry. [[ensures: invariant()]] // ...public function exit (if no throw). try { ... // Function body. @@ -665,8 +661,9 @@ For example, the following possible emulation of class invariants based on __P03 ... }; `` +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. ] -All references reviewed by the authors seem to not consider static and volatile member functions not supporting static and volatile invariants respectively. +All references reviewed by the authors seem to not consider static and volatile functions not supporting static and volatile invariants respectively. * Implementing subcontracting involves a significant amount of complexity and it seems to not be properly supported by any C++ library other than this one (especially when handling multiple inheritance, correctly copying postcondition old values across all overridden contracts deep in the inheritance tree, and correctly reporting the return value to the postconditions of overridden virtual functions in base classes). [footnote diff --git a/doc/extras.qbk b/doc/extras.qbk index 7164fec..6197001 100644 --- a/doc/extras.qbk +++ b/doc/extras.qbk @@ -13,39 +13,46 @@ This section can be consulted selectively for specific topics of interest. Old values require to copy the expression passed to [macroref BOOST_CONTRACT_OLDOF] thus the type of that expression must be copyable. More precisely, dereferencing an old value pointer of type [classref boost::contract::old_ptr]`` requires [classref boost::contract::is_old_value_copyable]`::value` to be `true` (otherwise this library will generate a compile-time error). -In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copyable (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use the old values). +In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copyable (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use these old values). In these cases, programmers can declare old values using [classref boost::contract::old_ptr] as seen so far. -However, in other cases it might be desirable to simply not check assertions that use old values when the respective old value types are not copyable. -Programmers can do this by using [classref boost::contract::old_ptr_if_copyable] instead of [classref boost::contract::old_ptr] to program these old values (and by checking if the old value pointer is not null before dereferencing it in postconditions). -For example, consider the following function template that could in general be instantiated for types `T` that are not copy constructible (that is for which `boost::contract::is_old_value_copyable::value` is `false`, see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +However, in some other cases it might be desirable to skip assertions that use old values when the respective old value types are not copyable. +Programmers can do this by using [classref boost::contract::old_ptr_if_copyable] instead of [classref boost::contract::old_ptr] to program these old values and by checking if the old value pointer is not null before dereferencing it in postconditions. +For example, consider the following function template that could in general be instantiated for types `T` that are not copy constructible (that is for which [classref boost::contract::is_old_value_copyable]`::value` is `false`, see [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [footnote *Rationale:* __N1962__ and other proposals to add contracts to C++ do not provide a mechanism to selectively disable copies for only old value types that are not copy constructible. However, this library provides such a mechanism to allow to program contracts for template code without necessarily adding extra copy constructible type requirements that would not be present if it were not for copying the old values (so compiling the code with and without contracts will not necessarily alter the type requirements of the program). -As for extending the C++ language, something similar could be achieved by combing both __N1962__ (contracts) and C++17 `if constexpr` so that old value expressions within template code could be guarded by `if constexpr` statements checking if the old value types are copyable or not. +Something similar could be achieved combing C++17 `if constexpr` with __N1962__ or __P0380__ so that old value expressions within template code could be guarded by `if constexpr` statements checking if the old value types are copyable or not. +For example, assuming old values are added to __P0380__ (e.g., via `oldof`) and that C++17 `if constexpr` can be used within __P0380__ contracts: +`` + template + void offset(T& x, int count) + [[ensures: if constexpr(std::is_copy_constructible::value) x == oldof(x) + count]] + ... +`` ] [import ../example/features/old_if_copyable.cpp] [old_if_copyable_offset] -The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_if_copyable] so if `T` is not copyable then `total` will simply not be copied and `old_total` will be left as a null pointer (in these cases `old_total` must be checked to be not null `if(old_total) ...` before it can be dereferenced in postconditions and exception guarantees). -If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error when `accumulate` is instantiated with types `T` that are not copy constructible (but only if `old_total` is actually dereferenced somewhere in the contract assertions using `*old_total ...`, `old_total->...`, etc.). +The old value pointer `old_x` is programmed using [classref boost::contract::old_ptr_if_copyable] so if `T` is not copyable then `x` will simply not be copied and `old_x` will be left as a null pointer (here `old_x` must be checked to be not null `if(old_x) ...` before it is dereferenced in postconditions and exception guarantees). +If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error when `offset` is instantiated with types `T` that are not copy constructible (but only if `old_x` is actually dereferenced somewhere in the contract assertions using `*old_x ...`, `old_x->...`, etc.). When C++11 `auto` declarations are used with [macroref BOOST_CONTRACT_OLDOF], this library always defaults to using the [classref boost::contract::old_ptr] type (because this type requirements are more stringent, if programmers want to relax the copyable type requirement they must do so explicitly by using [classref boost::contract::old_ptr_if_copyable] instead of using `auto`). For example, the following will use [classref boost::contract::old_ptr] and not [classref boost::contract::old_ptr_if_copyable] to declare `old_x`: - auto old_x = BOOST_CONTRACT_OLDOF(x); // C++11 auto declarations. + auto old_x = BOOST_CONTRACT_OLDOF(x); // C++11 auto declarations always use `old_ptr` (never `old_ptr_if_copyable`). This library internally uses [classref boost::contract::is_old_value_copyable] to determine if an old value type is copyable or not, and then [classref boost::contract::old_value_copy] to actually copy the old value. -By default, `boost::contract::is_old_value_copyable` is equivalent to `boost::is_copy_constructible` and `boost::contract::old_value_copy` is implemented using `T`'s copy constructor. -However, the type traits provided by this library can be specialized to avoid making old value copies of types even when they have a copy constructor (because these copy constructors might be expensive, etc.) or, on the flip side, to make old value copies for types that do not have a copy constructor. -For example, the following specialization of [classref boost::contract::is_old_value_copyable] will avoid making old value copies for all expressions of type `w` even if that type has a copy constructor (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +By default, [classref boost::contract::is_old_value_copyable]`` is equivalent to `boost::is_copy_constructible` and [classref boost::contract::old_value_copy]`` is implemented using `T`'s copy constructor. +However, these type traits can be specialized by programmers for example to avoid making old value copies of types even when they have a copy constructor (maybe because these copy constructors are too expensive), or to make old value copies for types that do not have a copy constructor, or for any other specific need programmers might have for the types in question. +For example, the following specialization of [classref boost::contract::is_old_value_copyable] intentionally avoids making old value copies for all expressions of type `w` even if that type has a copy constructor (see [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [old_if_copyable_w_decl] [old_if_copyable_w_spec] -While the following specializations of [classref boost::contract::is_old_value_copyable] and [classref boost::contract::old_value_copy] make old value copies of expressions of type `p` even if that type does not have a copy constructor (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +On the flit side, the following specializations of [classref boost::contract::is_old_value_copyable] and [classref boost::contract::old_value_copy] make old value copies of expressions of type `p` even if that type does not actually have a copy constructor (see [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [old_if_copyable_p_decl] [old_if_copyable_p_spec] @@ -54,7 +61,7 @@ While the following specializations of [classref boost::contract::is_old_value_c In general, `boost::contract::is_copy_constructible` and therefore [classref boost::contract::is_old_value_copyable] require C++11 `decltype` and SFINAE to automatically detect if a given type is not copyable. On non-C++11 compilers, it is possible to inherit the old value type from `boost::noncopyable`, or use `BOOST_MOVABLE_BUT_NOT_COPYABLE`, or specialize `boost::is_copy_constructible` (see [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html `boost::is_copy_constructible`] documentation for more information). -Alternatively, it is possible to just specialize [classref boost::contract::is_old_value_copyable], for example for a non-copyable type `n` (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +Alternatively, it is possible to just specialize [classref boost::contract::is_old_value_copyable], for example for a non-copyable type `n` (see [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [old_if_copyable_n_decl] [old_if_copyable_n_spec] @@ -63,26 +70,57 @@ Alternatively, it is possible to just specialize [classref boost::contract::is_o [section Assertion Requirements (Templates)] -In general, assertions can introduce a new set of requirements on the types used by the program. +In general, assertions can introduce a new set of requirements on the types used by a program. Some of these type requirements might be necessary only to check the assertions and they would not be required by the program otherwise. -In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses types that do not provide all the operations needed to check contract assertions (because it is not possible to fully check the correctness of the program as stated by the contracts). +In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses types that do not provide all the operations needed to check contract assertions (because it is not possible to fully check the correctness of the program as specified by its contracts). In these cases, programmers can specify contract assertions as we have seen so far, compilation will fail if user types do not provide all operations necessary to check the contracts. -However, in other cases it might be desirable that adding contracts to a program does not alter its type requirements and that assertions are simply not checked when user types do not provide all the operations necessary to check the assertions. -Programmers can do this by using [funcref boost::contract::condition_if] (or [funcref boost::contract::condition_if_c]) within the contract assertions. +However, in some other cases it might be desirable to not augment the type requirements of a program because of contract assertions and to skip these assertions when user types do not provide all the operations necessary to check them. +Programmers can do this by using [funcref boost::contract::condition_if] (or [funcref boost::contract::condition_if_c]). For example, let's consider the following `vector` class template. This class template does not usually require that its type parameter `T` has an equality operator `==` (it only requires `T` to be copy constructible, see `std::vector` documentation). -However, the contracts of the `vector::push_back(value)` member function include a postcondition `back() == value` which introduces the new requirement that `T` must also have an equality operator `==`. +However, the contracts for the `vector::push_back(value)` public function include a postcondition `back() == value` that introduces the new requirement that `T` must also have an equality operator `==`. Programmers can specify this postcondition as usual with `BOOST_CONTRACT_ASSERT(back() == value)` an let the program fail to compile when users instantiate `vector` with a type `T` that does not provide an equality operator `==`. -Otherwise, programmers can specify this postcondition using [funcref boost::contract::condition_if] to evaluate the asserted condition only for types `T` that have an equality operator `==` and trivially evaluate to `true` otherwise, for example (see also [@../../example/features/condition_if.cpp =condition_if.cpp=]): +Otherwise, programmers can specify this postcondition using [funcref boost::contract::condition_if] to evaluate the asserted condition only for types `T` that have an equality operator `==` (and trivially evaluate to `true` otherwise). +On C++17 compilers, the same can be achieved using `if constexpr` instead of [funcref boost::contract::condition_if] resulting in a more concise and readable syntax. +For example (see [@../../example/features/condition_if.cpp =condition_if.cpp=]): [import ../example/features/condition_if.cpp] -[condition_if] +[table +[[Until C++17 (without `if constexpr`)][Since C++17 (with `if constexpr`)]] +[[[condition_if]] [`` +template +class vector { +public: + void push_back(T const& value) { + boost::contract::check c = boot::contract::public_function(this) + .postcondition([&] { + // Guard with `if constexpr` for T without `==`. + if constexpr(boost::has_equal_to::value) + BOOST_CONTRACT_ASSERT(back() == value); + }) + ; + + vect_.push_back(value); + } + + + + + + + + /* ... */ +``]] +] The [funcref boost::contract::condition_if] function template is a special case of the more general facility [funcref boost::contract::call_if]: -Specifically, `boost::contract::condition_if<`[^['Predicate]]`>(`[^['condition]]`)` is equivalent to: +Specifically, [funcref boost::contract::condition_if]`<`[^['Predicate]]`>(`[^['condition]]`)` is equivalent to: +[footnote +For optimization reasons, the internal implementation of [funcref boost::contract::condition_if] does not actually uses [funcref boost::contract::call_if] (but in principle [funcref boost::contract::condition_if] could be implemented using [funcref boost::contract::call_if] as shown in this documentation). +] boost::contract::call_if<``[^['Predicate]]``>( ``[^['condition]]`` @@ -93,7 +131,7 @@ Specifically, `boost::contract::condition_if<`[^['Predicate]]`>(`[^['condition]] Where [^['Predicate]] is a nullary boolean meta-function and [^['condition]] is a nullary boolean functor. If [^['Predicate]]`::value` is statically evaluated to be `true` at compile-time then [^['condition]]`()` is called at run-time and its boolean result is returned by the enclosing `call_if`. Otherwise, if [^['Predicate]]`::value` is statically evaluated to be `false` at compile-time then the lambda function `[] { return true; }()` is called at run-time and `true` is trivially returned by the enclosing `call_if`. -Note that [^['condition]] must be a functor template (and not just a functor) so its code that contains the assertion operations with the extra type requirements (e.g., the equality operator `==`) will not be instantiated and compiled for specific types unless the compiler determines that [^['condition]]`()` needs to be actually called at run-time (functor templates like `std::equal_to` and C++14 generic lambdas can be used to program [^['condition]], but C++11 lambdas cannot). +Therefore, if [^['condition]] is a functor template (and not just a functor) then its code that contains the assertion operations with the extra type requirements (e.g., the equality operator `==`) will not be instantiated and compiled for specific types unless the compiler determines at compile-time that [^['Predicate]]`::value` is `true` (functor templates like `std::equal_to` and C++14 generic lambdas can be used to program [^['condition]], but C++11 lambdas cannot). More in general, [funcref boost::contract::call_if] accepts a number of optional /else-if/ statements and one optional /else/ statement: @@ -113,26 +151,11 @@ At run-time [funcref boost::contract::call_if] will call the functor [^['then1]] If [^['then1]], [^['then2]], ..., [^['else]] are nullary functor templates (not just nullary functors) then their code will only be compiled if the compiler determines they need to be actually called at run-time (so only if the related [^['Predicate1]]`::value`, [^['Predicate2]]`::value`, ... are evaluated to be `true` or `false` at compile-time). All the `else_if<...>(...)` statements are optional, the `else_(...)` statement is optional if the functor calls return `void` but it is required otherwise. -In general, [funcref boost::contract::call_if] can be used to program contract assertions that compile and check different functor templates depending on related conditions being statically evaluated to be `true` or `false` at compile-time (but in most cases [funcref boost::contract::condition_if] should be sufficient, simpler and less verbose to use). -The [funcref boost::contract::condition_if_c], [funcref boost::contract::call_if_c], and `.else_if_c` function templates work similarly to their counterparts without the `..._c` postfix above, but they take their condition template parameters as static boolean values instead of nullary boolean meta-functions. +In general, [funcref boost::contract::call_if] can be used to program contract assertions that compile and check different functor templates depending on related predicates being statically evaluated to be `true` or `false` at compile-time (but in most cases [funcref boost::contract::condition_if] should be sufficient and less verbose to use). +The [funcref boost::contract::condition_if_c], [funcref boost::contract::call_if_c], and `.else_if_c` function templates work similarly to their counterparts without the `..._c` postfix above, but they take their predicate template parameters as static boolean values instead of nullary boolean meta-functions. -[heading Static-If Emulation (C++14)] - -The [funcref boost::contract::call_if] function template is a general facility and its use is not limited to programming contracts. -In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`, for example (see also [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): - -[import ../example/features/call_if_cxx14.cpp] -[call_if_cxx14] - -This implementation is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching (but of course a similar implementation using C++17 `if constexpr` would be even more readable and concise). -[footnote -Boost.Hana (`boost::hana::if_`) can also be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`. -] - -[heading Static-If (C++17)] - -Another example where assertion requirements might be useful is to disable assertions in that might be constant-correct for specific template types. -For example, `std::distance` does not alter its iterator arguments but only for forward iterators so the follow template function evaluates its preconditions only for for these types: +Another example where assertion requirements might be useful is to disable assertions that might be constant-correct only for specific template types. +For example, `std::distance` does not alter its iterator arguments but only for forward iterators so the follow template function evaluates its preconditions only for for those types (for convenience this example uses C++17 `if constexpr` but it could have been implemented using [funcref boost::contract::condition_if] together with C++14 generic lambdas or binding to a C++11 functor template that calls `std::distance` in its `operator()`): template void display_first_second_next(InputIter begin, InputIter end) { @@ -146,7 +169,37 @@ For example, `std::distance` does not alter its iterator arguments but only for ... } -(For convenience this example used C++17 `if constexpr` but it could have been similarly implemented using C++14 generic lambdas or in C++11 using binding to a functor template that calls `std::distance` in its `operator()`.) + +[heading If-Constexpr Emulation (C++14)] + +The [funcref boost::contract::call_if] function template is a general facility and its use is not limited to programming contracts. +In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`, for example (see [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): +[footnote +Boost.Hana (`boost::hana::if_`) can also be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`. +] + +[import ../example/features/call_if_cxx14.cpp] +[table +[[Until C++17 (without `if constexpr`)][Since C++17 (with `if constexpr`)]] +[[[call_if_cxx14]] [`` +template +void myadvance(Iter& i, Dist n) { + if constexpr(is_random_access_iterator::value) { + i += n; + } else if constexpr(is_bidirectional_iterator::value) { + if(n >= 0) while(n--) ++i; + else while(n++) --i; + } else if constexpr(is_input_iterator::value) { + while(n--) ++p; + } else { + static_assert(false, "requires at least input iterator"); + } +} +``]] +] + +This implementation is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching. +Of course the implementation that uses C++17 `if constexpr` is even more readable and concise. [endsect] @@ -169,8 +222,8 @@ This is consistent with `static` class invariants that are checked even before ` * Both mutable and `const` public member functions check `const` qualified invariants (at entry and at exit). * Both `volatile` and `const volatile` public member functions check `const volatile` qualified invariants (at entry and at exit). -The above rules ensure that volatile class invariants are correctly checked (see also __Constructor_Calls__, __Destructor_Calls__, and __Public_Function_Calls__). -For example (see also [@../../example/features/volatile.cpp =volatile.cpp=]): +The above rules ensure that volatile class invariants are correctly checked (see __Constructor_Calls__, __Destructor_Calls__, and __Public_Function_Calls__). +For example (see [@../../example/features/volatile.cpp =volatile.cpp=]): [import ../example/features/volatile.cpp] [volatile] @@ -207,14 +260,14 @@ As usual, static class invariants can also be specified (see __Class_Invariants_ [section Move Operations] -As with all public operations of a class, also move operations should maintain class invariants (see also __Stroustrup13__, p. 520). +As with all public operations of a class, also move operations should maintain class invariants (see __Stroustrup13__, p. 520). Specifically, C++ requires the following: * The moved-from object can be copy assigned. * The moved-from object can be move assigned. -* The moved-from object can be destroyed (if not for anything else, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires class invariants to be satisfied at its destructor entry, as always with destructors see also __Destructor_Calls__). +* The moved-from object can be destroyed (if not for anything else, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires class invariants to be satisfied at its destructor entry, as always with destructors see __Destructor_Calls__). -Thus both the move constructor and the move assignment operator need to maintain the class invariants of the moved-from object and their contracts can be programmed using [funcref boost::contract::constructor] and [funcref boost::contract::public_function] as always for constructors and public member functions, for example (see also [@../../example/features/move.cpp =move.cpp=]): +Thus both the move constructor and the move assignment operator need to maintain the class invariants of the moved-from object and their contracts can be programmed using [funcref boost::contract::constructor] and [funcref boost::contract::public_function] as always for constructors and public member functions, for example (see [@../../example/features/move.cpp =move.cpp=]): [import ../example/features/move.cpp] [move] @@ -236,7 +289,7 @@ Therefore, unless these operations are not public or they have no preconditions, In C++, a `union` cannot have virtual member functions, bases classes, and cannot be used as a base class thus subcontracting ([classref boost::contract::virtual_], [macroref BOOST_CONTRACT_OVERRIDE], etc.) do not apply to unions. Also a `union` cannot inherit from [classref boost::contract::constructor_precondition] (because it cannot have base classes) so such a class is used to declare a local object that checks constructor preconditions (see `pre` in the example below). -A part from that, this library is used as usual to program contracts for unions, for example (see also [@../../example/features/union.cpp =union.cpp=]): +A part from that, this library is used as usual to program contracts for unions, for example (see [@../../example/features/union.cpp =union.cpp=]): [import ../example/features/union.cpp] [union] @@ -245,7 +298,7 @@ A part from that, this library is used as usual to program contracts for unions, [section Disable Contract Checking (and Assertion Levels)] -Checking contracts adds run-time overhead and can slow down program execution (see also __Benefits_and_Costs__). +Checking contracts adds run-time overhead and can slow down program execution (see __Benefits_and_Costs__). Therefore, programmers can define the following configuration macros (`-D` option in Clang and GCC, `/D` option in MSVC, etc.) to instruct this library to not check specific kind of contract conditions at run-time: * Define the [macroref BOOST_CONTRACT_NO_PRECONDITIONS] macro to not check preconditions. @@ -268,7 +321,7 @@ Old values can be used by both postconditions and exception guarantees so it is [heading Assertion Levels] Programmers can use `#if` (or `if`) statements to implement different contract /assertion levels/ that selectively enable and disable assertion checking at compile-time (or run-time). -For example, programmers could define an "audit" level for computationally expensive assertions that alter the computational complexity of the enclosing function and an "axiom" level for computationally prohibitive assertions that should always be excluded from program execution (these are similar to the "audit" and "axiom" assertion levels proposed in __P0380__, see also [@../../example/features/ifdef_audit.cpp =ifdef_audit.cpp=]): +For example, programmers could define an "audit" level for computationally expensive assertions that alter the computational complexity of the enclosing function and an "axiom" level for computationally prohibitive assertions that should always be excluded from program execution (these are similar to the "audit" and "axiom" assertion levels proposed in __P0380__, see [@../../example/features/ifdef_audit.cpp =ifdef_audit.cpp=]): [import ../example/features/ifdef_audit.cpp] [ifdef_audit] @@ -299,7 +352,7 @@ Instead, these macros are automatically defined by this library based on users d Alternatively, this library provides a macro-based interface [headerref boost/contract_macro.hpp] that can also be used to completely disable compile-time overhead of contract code. The macro interface is more concise than using `#ifndef` statements but it makes the contract code and eventual compiler errors more cryptic (because all the macro code will expand on a single line number, etc. as always with C++ macros). -The following example illustrates both the use of the macro interface and of `#ifndef` statements to selectively disable not just contract checking at run-time but contract code compilation altogether (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): +The following example illustrates both the use of the macro interface and of `#ifndef` statements to selectively disable not just contract checking at run-time but contract code compilation altogether (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): [import ../example/features/ifdef_macro.cpp] [import ../example/features/ifdef.cpp] @@ -310,7 +363,7 @@ The following example illustrates both the use of the macro interface and of `#i The same is done to disable contract code complication for private and protected functions. The [macroref BOOST_CONTRACT_OLD_PTR_IF_COPYABLE] macro is provided to handle non-copyable old value types. -For constructors, destructors, and public functions instead (see also [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): +For constructors, destructors, and public functions instead (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.pp =ifdef.cpp=]): [table [ [Macro Interface] [Code Interface] ] @@ -326,7 +379,7 @@ In most cases, the compile-time overhead of contracts should not represent an is [section Separate Body Implementation] -Contracts are part of the program specification and not of its implementation (see also __Specification_vs_Implementation__). +Contracts are part of the program specification and not of its implementation (see __Specification_vs_Implementation__). However, this library uses function definitions to program the contracts so contract code appears together with the function implementation code. This is not ideal (even if contract code programmed with this library must always appear at the very top of the function definition so programmers will easily be able to distinguish it from the rest of function implementation so this might not be real problem in practise). @@ -338,12 +391,12 @@ In such cases, the function implementation can be programmed in an extra /body f The original function definition remains in the header files instead, it contains the contract and then simply calls the extra body function. This technique allows to keep the contract code in header files while separating the body implementation code to source files but at the cost of programmers writing an extra function declaration for the body function (with the limitation that constructor member initialization lists must also be programmed in the header files because that is where the constructors that call their extra body functions will be actually defined). -For example, the following header file only contains function declarations and contract code (function specifications) and constructor member initializations (see also [@../../example/features/separate_body.hpp =separate_body.hpp=]): +For example, the following header file only contains function declarations and contract code (function specifications) and constructor member initializations (see [@../../example/features/separate_body.hpp =separate_body.hpp=]): [import ../example/features/separate_body.hpp] [separate_body_hpp] -Instead, the function bodies (function implementations) is programmed in a separate source file (see also [@../../example/features/separate_body.cpp =separate_body.cpp=]): +Instead, the function bodies (function implementations) is programmed in a separate source file (see [@../../example/features/separate_body.cpp =separate_body.cpp=]): [import ../example/features/separate_body.cpp] [separate_body_cpp] @@ -367,14 +420,14 @@ This section shows how to use this library without C++11 lambda functions. This has some advantages: * It allows to use this library on compilers that do not support C++11 lambda functions (essentially most C++03 compilers can be used in that case, see __No_Macros__ to also avoid using variadic macros). -* Contract functions (see 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 also __Constant_Correctness__). +* Contract functions (see 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 (e.g., `[const&] (...) { ... }` or `[const& `[^['variable-name]]`] (...) { ... }`) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. Note that C++11 lambda allows 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 an extra copy that might be too expensive in general. ] * Contract specifications are automatically separated from function body implementations (see __Separate_Body_Implementation__). -However, not using C++11 lambda functions comes to the significant cost of having to manually write a great deal of boiler-plate code, for example (see also [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=] and [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): +However, not using C++11 lambda functions comes to the significant cost of having to manually write a great deal of boiler-plate code, for example (see [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=] and [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): [import ../example/features/no_lambdas.hpp] [no_lambdas_hpp] @@ -382,23 +435,23 @@ However, not using C++11 lambda functions comes to the significant cost of havin [import ../example/features/no_lambdas.cpp] [no_lambdas_cpp] -If programmers also want to fully enforce all contract programming constant-correctness requirements at compile-time, they should follow these rules when programming the contract functions (see also __Constant_Correctness__): +If programmers also want to fully enforce all contract programming constant-correctness requirements at compile-time, they should follow these rules when programming the contract functions (see __Constant_Correctness__): * Precondition functions (i.e., the `..._precondition` functions in the example above) can take their arguments either by `const` value or by `const&`, and they should be either `static` or `const` member functions. * Postcondition functions (i.e., the `..._postcondition` functions in the example above) should take their arguments by `const&`, and they should be either `static` or `const` member functions. * Old value functions (i.e., the `..._old` functions in the example above) should take their arguments by `const&` a part from old value pointers that should be taken by `&` (so only old value pointers can be modified), and they should be either `static` or `const` member functions. -* Constructor precondition and old value functions should be `static` (because constructor preconditions and old values cannot access the object `this`, see also __Constructor_Calls__). -* Destructor postcondition functions should be `static` (because destructor postconditions cannot access the object `this`, see also __Destructor_Calls__). +* Constructor precondition and old value functions should be `static` (because constructor preconditions and old values cannot access the object `this`, see __Constructor_Calls__). +* Destructor postcondition functions should be `static` (because destructor postconditions cannot access the object `this`, see __Destructor_Calls__). -Note that the extra contract functions also allow to program only the contract code in the header file (see also __Specification_vs_Implementation__). +Note that the extra contract functions also allow to program only the contract code in the header file (see __Specification_vs_Implementation__). All function body implementation code was instead programmed in the source file (including the constructor member initialization list, that could not be done with the technique shown in __Separate_Body_Implementation__). [footnote In this example, `bind` was used to generate nullary functors from the contract functions. As always with `bind`, `cref` and `ref` must be used to bind arguments by `const&` and `&` respectively, plus it might be necessary to explicitly `static_cast` the function pointer passed to `bind` in case the bound function name is overloaded. ] -Also note that the contract functions can always be declared `private` if programmers need to exactly control the public members of the class (this was not done in this example only for brevity, see also __Access_Specifiers__). +Also note that the contract functions can always be declared `private` if programmers need to exactly control the public members of the class (this was not done in this example only for brevity, see __Access_Specifiers__). -Alternatively, on compilers that do not support C++11 lambda functions but that support type-of (either native as an extension or via emulation, these should be most recent C++03 compilers), [@http://www.boost.org/doc/libs/release/libs/local_function/doc/html/index.html Boost.LocalFunction] can be used to program the contract functions, for example (see also [@../../example/features/no_lambdas_local_func.cpp =no_lambda_local_func.cpp=]): +Alternatively, on compilers that do not support C++11 lambda functions but that support type-of (either native as an extension or via emulation, these should be most recent C++03 compilers), [@http://www.boost.org/doc/libs/release/libs/local_function/doc/html/index.html Boost.LocalFunction] can be used to program the contract functions, for example (see [@../../example/features/no_lambdas_local_func.cpp =no_lambda_local_func.cpp=]): [import ../example/features/no_lambdas_local_func.cpp] [no_lambdas_local_func] @@ -417,7 +470,7 @@ The only macro that cannot be programmed manually is [macroref BOOST_CONTRACT_OV [note Some of this library macros are variadic macros, others are not (see below). -Variadic macros were officially added to the language since C++11 but most compilers have been supporting variadic macros as an extension for a long time, plus essentially all compilers that support C++11 lambda functions also support C++11 variadic macros (and this library might rarely be used without the convenience of C++11 lambda functions, see also __No_Lambda_Functions__). +Variadic macros were officially added to the language since C++11 but most compilers have been supporting variadic macros as an extension for a long time, plus essentially all compilers that support C++11 lambda functions also support C++11 variadic macros (and this library might rarely be used without the convenience of C++11 lambda functions, see __No_Lambda_Functions__). [footnote In any case, compilation times of this library were measured to be comparable between compilers that support variadic macros and compilers that do not. See also [macroref BOOST_CONTRACT_MAX_ARGS] on compilers that do not support variadic macros. @@ -434,6 +487,7 @@ These macros cannot be programmed manually but they are not variadic macros so p [footnote *Rationale:* These macros expand SFINAE-based introspection templates that are too complex to be programmed manually by users (that remains the case even if C++14 generic lambdas were to be used here). +On a related note, in theory using C++14 generic lambdas, the [macroref BOOST_CONTRACT_OVERRIDE] macro could be re-implemented in a way that can be expanded at function scoped, instead of class scoped (but there is not really a need for that). ] The [macroref BOOST_CONTRACT_OVERRIDES] macro is a variadic macro instead but programmes can manually repeat the non-variadic macro [macroref BOOST_CONTRACT_OVERRIDE] for each overriding public function name on compilers that do not support variadic macros. @@ -444,7 +498,7 @@ This is not a variadic macro and programmers should be able to use it on all C++ In any case, the invocation `BOOST_CONTRACT_ASSERT(`[^['condition]]`)` simply expands to code equivalent to the following: [footnote *Rationale:* -No need to also support C++11 `__func__` because it always expands to `operator()` for lambdas functions (which are typically used to program contract assertions). +No need to also support C++11 `__func__` because it always expands to the name of `operator()` of the functor used to program the contract assertions (e.g., of the lambda function) and not to the name of the actual function specifying the contract. ] if(!(``[^['condition]]``)) { @@ -452,7 +506,7 @@ No need to also support C++11 `__func__` because it always expands to `operator( BOOST_PP_STRINGIZE(``[^['condition]]``)); } -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., see also __Throw_on_Failure__). +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., see __Throw_on_Failure__). If there is a need for it, programmers can always program contract assertions that throw specific exceptions as follow (see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=] for an example): if(!``[^['condition]]``) throw ``[^['exception-object]]``; @@ -462,12 +516,12 @@ However, using [macroref BOOST_CONTRACT_ASSERT] is convenient because it always [heading Base Types (Variadic)] As shown in __Base_Classes__, this library provides the [macroref BOOST_CONTRACT_BASE_TYPES] variadic macro to declare the `base_types` member type that lists all public bases of a derived class. -Programmers can also declare `base_types` without using [macroref BOOST_CONTRACT_BASE_TYPES] at the cost of writing a bit more code manually, for example (see also [@../../example/features/base_types_no_macro.cpp =base_types_no_macro.cpp=]): +Programmers can also declare `base_types` without using [macroref BOOST_CONTRACT_BASE_TYPES] at the cost of writing a bit more code manually, for example (see [@../../example/features/base_types_no_macro.cpp =base_types_no_macro.cpp=]): [import ../example/features/base_types_no_macro.cpp] [base_types_no_macro] -The `base_types` member type must be a `boost::mpl::vector` which must list /only/ `public` base classes (because only public bases subcontract, see also __Function_Calls__), and in the same order these public base classes appear in the derived class inheritance list. +The `base_types` member type must be a `boost::mpl::vector` which must list /only/ `public` base classes (because only public bases subcontract, see __Function_Calls__), and in the same order these public base classes appear in the derived class inheritance list. If the [macroref BOOST_CONTRACT_BASE_TYPES] macro is not used, it is the responsibility of the programmers to maintain the correct list of bases in the `boost::mpl::vector` each time the derived class inheritance list changes (this might complicate maintenance). In general, it is recommended to use the [macroref BOOST_CONTRACT_BASE_TYPES] macro whenever possible. @@ -475,7 +529,7 @@ In general, it is recommended to use the [macroref BOOST_CONTRACT_BASE_TYPES] ma [heading Old Values (Variadic)] As shown in __Old_Values__, this library provides the [macroref BOOST_CONTRACT_OLDOF] variadic macro to assign old value copies. -Programmers can also assign old values without using [macroref BOOST_CONTRACT_OLDOF] at the cost of writing a bit more code manually, for example (see also [@../../example/features/old_no_macro.cpp =old_no_macro.cpp=]): +Programmers can also assign old values without using [macroref BOOST_CONTRACT_OLDOF] at the cost of writing a bit more code manually, for example (see [@../../example/features/old_no_macro.cpp =old_no_macro.cpp=]): [import ../example/features/old_no_macro.cpp] [old_no_macro] @@ -484,8 +538,8 @@ The ternary operator `boost::contract::copy_old(v) ? size() : boost::contract::n The enclosing [funcref boost::contract::make_old] copies the old value expression and creates an old value pointer. Otherwise, [funcref boost::contract::null_old] indicates that a null old value pointer should be created. -The [funcref boost::contract::make_old] and [funcref boost::contract::copy_old] functions are used exactly as above but without the extra `v` parameter when they are called from within non-virtual functions (see also __Public_Function_Overrides__). -The old value pointer returned by [funcref boost::contract::make_old] can be assigned to either [classref boost::contract::old_ptr] or [classref boost::contract::old_ptr_if_copyable] (see also __Old_Value_Requirements__). +The [funcref boost::contract::make_old] and [funcref boost::contract::copy_old] functions are used exactly as above but without the extra `v` parameter when they are called from within non-virtual functions (see __Public_Function_Overrides__). +The old value pointer returned by [funcref boost::contract::make_old] can be assigned to either [classref boost::contract::old_ptr] or [classref boost::contract::old_ptr_if_copyable] (see __Old_Value_Requirements__). In general, it is recommended to use the [macroref BOOST_CONTRACT_OLDOF] macro whenever possible. diff --git a/doc/getting_started.qbk b/doc/getting_started.qbk index a6697be..1d98dfb 100644 --- a/doc/getting_started.qbk +++ b/doc/getting_started.qbk @@ -6,20 +6,21 @@ [section Getting Started] -This section gives preliminary information to get oriented in using this library. +This section illustrates how to setup a system to use this library. [section This Documentation] -Programmers should be able to start using this library after reading the __Introduction__, __Getting_Started__, and __Tutorial__ sections. -The __Advanced_Topics__ and other sections of this documentation can be consulted at a later point to gain a more in-depth knowledge of the library. +Programmers should be able to start using this library after reading __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 well familiar with the contract programming methodology. -Some of the source code of the examples linked by this documentation contains special code comments of the form `//[...` and `//]`. +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. [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 these examples is to illustrate how to use this library and not to represent real product code. +Also the purpose of all examples in 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. @@ -31,11 +32,11 @@ These explain reasons behind decisions made during the design and implementation In general, this library requires a C++ compiler with support for SFINAE and other template meta-programming techniques part of the C++03 standard. This library requires Boost (Boost.Optional, Boost.Thread, Boost.FunctionTypes, Boost.Traits, Boost.MPL, etc.). -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 functions to specify preconditions and postconditions (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 modern C++ compilers support variadic macros even before C++99 and C++11, see __No_Macros__). +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 equivalent to C++11 `decltype(...)`. -However, this library does not actually use type deduction in these cases (because the library already knows the types in question) so C++11 `decltype` and other type-of implementations are not required to compile this library (that is why [^['type-of]] and not the actual `decltype` operator is used in these cases). +Some parts of this documentation use an operator [^['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: @@ -74,9 +75,9 @@ All headers required by this library can be included at once by: 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). 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. -Files in =boost/contract/detail/=, names in the `boost::contract::detail` namespace, macros starting with `BOOST_CONTRACT_DETAIL...`, and 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. +Files in =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 error messages reported by the compiler might help troubleshooting). +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] @@ -89,21 +90,19 @@ The steps below show how to compile this library as a shared library (a.k.a., Dy [warning By default, this library is compiled as a shared library (in which case this library automatically defines the [macroref BOOST_CONTRACT_DYN_LINK] macro). -[footnote -*Rationale:* -[macroref BOOST_CONTRACT_DYN_LINK] is named similarly to [macroref BOOST_ALL_DYN_LINK]. -] - There are configuration macros [macroref BOOST_CONTRACT_STATIC_LINK] and [macroref BOOST_CONTRACT_HEADER_ONLY] that can be defined to compile this library as a static or header-only library respectively. [footnote *Rationale:* -[macroref BOOST_CONTRACT_STATIC_LINK] and [macroref BOOST_CONTRACT_HEADER_ONLY] are named similarly to `BOOST_ALL_DYN_LINK` and `BOOST_CHRONO_HEADER_ONLY`. +[macroref BOOST_CONTRACT_DYN_LINK], [macroref BOOST_CONTRACT_STATIC_LINK], and [macroref BOOST_CONTRACT_HEADER_ONLY] are named after `BOOST_ALL_DYN_LINK`, `BOOST_ALL_DYN_LINK`, and `BOOST_CHRONO_HEADER_ONLY` respectively. ] -However, the use of [macroref BOOST_CONTRACT_STATIC_LINK] and [macroref BOOST_CONTRACT_HEADER_ONLY] is strongly discouraged because this library is not guaranteed to always work correctly at run-time when these macros are defined. -Specifically, this library will 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 being used by different program units (different programs, different libraries of the same program, etc.). +The use of [macroref BOOST_CONTRACT_STATIC_LINK] and [macroref BOOST_CONTRACT_HEADER_ONLY] is discouraged because this library is not guaranteed to always work correctly at run-time when these macros are defined. +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 being used by different program units (different programs, different shared libraries of the same program, etc.). +However, [macroref BOOST_CONTRACT_STATIC_LINK] and [macroref BOOST_CONTRACT_HEADER_ONLY] can be used for applications that check contracts in a single program unit (e.g., a single program with only statically linked libraries that check contracts). ] +[heading Visual Studio (MSVC)] + Using MSVC on Windows (from a developer command prompt that automatically invokes the correct =vcvarsall.bat=): [pre @@ -121,7 +120,9 @@ Using MSVC on Windows (from a developer command prompt that automatically invoke > introduction ] -Using GCC on Cygwin (and some Linux-like OS): +[heading GCC and CLang] + +Using GCC on Cygwin (or some Linux-like OS): [pre $ cd ['lib-root]\/build @@ -138,21 +139,22 @@ $ export PATH=$PATH:['lib-root]\/build $ .\/introduction ] -The above steps also work for Clang using =clang++= instead of =g++=. +The above steps also work for Clang replacing =g++= with =clang++=. + +[heading BJam] Alternatively, programmers can setup their build environments (BJam, Make, CMake, MSBuild, etc.) to compile this library source code into a shared library and then compile and link user code against it (if that is preferred instead of manually running the compiler as indicated by the steps above). -For example, this library source comes with a complete set of Boost.Build (BJam) files that can be used to build the library, build and run its tests and examples (see [@../../example/Jamfile.v2 =example/Jamfile.v2=], [@../../test/Jamfile.v2 =test/Jamfile.v2=], [@../../build/Jamfile.v2 =build/Jamfile.v2=], [@../../build/boost_contract_no.jam =build/boost_contract_no.jam=], [@../../Jamroot =Jammroot=], etc.). -Assuming that: +For example, this library source comes with a complete set of Boost.Build (BJam) files that can be used to build the library, build and run its tests and examples (see [@../../example/Jamfile.v2 =example/Jamfile.v2=], [@../../test/Jamfile.v2 =test/Jamfile.v2=], [@../../build/Jamfile.v2 =build/Jamfile.v2=], [@../../build/boost_contract_no.jam =build/boost_contract_no.jam=], [@../../Jamroot =Jammroot=], etc.), assuming that: * Boost was installed and built from source. * An environment variable named `BOOST_ROOT` is set to the [^['boost-root]] directory path. * The `bjam` program can be found in the `PATH` environment variable. -Then the following uses BJam to build and run the [@../../example/features/introduction.cpp =introduction.cpp=] program and also to automatically build this library when necessary: +Then the following uses BJam to build and run the [@../../example/features/introduction.cpp [^['lib-root]/example/features/introduction.cpp]] program and also to automatically build this library if necessary: [pre -> cd ['lib-root]\example -> bjam features-introduction +$ cd ['lib-root]/example +$ bjam features-introduction ] [endsect] diff --git a/doc/introduction.qbk b/doc/introduction.qbk index 68a9de4..dcca586 100644 --- a/doc/introduction.qbk +++ b/doc/introduction.qbk @@ -9,15 +9,15 @@ Contract Programming allows to specify preconditions, postconditions, and class invariants that are automatically checked when functions are executed at run-time. These conditions assert program specifications within the source code itself allowing to find bugs more quickly during testing, making the code self-documenting, and increasing overall software quality (see __Contract_Programming_Overview__). -For example, consider the following function `inc` that increments its argument `x` by `1` and let's write its contract using code comments (see also [@../../example/features/introduction_comments.cpp =introduction_comments.cpp=]): +For example, consider the following function `inc` that increments its argument `x` by `1` and let's write its contract using code comments (see [@../../example/features/introduction_comments.cpp =introduction_comments.cpp=]): [import ../example/features/introduction_comments.cpp] [introduction_comments] -The precondition states that at function entry the argument `x` must be strictly smaller than the maximum allowable value of its type (so it can be increased by `1` without overflowing). -The postcondition states that at function exit the argument `x` must be incremented by `1` with respect to the value it had before executing the function indicated with `oldof(x)` (note that postconditions should be checked only when the execution of the function body did not throw an exception). +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). -Now let's program this function and its contract using this library (see also [@../../example/features/introduction.cpp =introduction.cpp=]): +Now let's program this function and its contract using this library (see [@../../example/features/introduction.cpp =introduction.cpp=] and __Non_Member_Functions__): [import ../example/features/introduction.cpp] [introduction] @@ -28,13 +28,13 @@ When the above function `inc` is called, this library will: * 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). -For example, if there is a bug in the code calling `inc` so that the function is called with `x` greater than or equal to `std::numeric_limits::max()` then the program will terminate with an error message similar to the following (so it will be evident that the bug is in the calling code): +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): [pre precondition assertion "x < std::numeric_limits::max()" failed: file "introduction.cpp", line 17 ] -Instead, if there is a bug in the implementation of `inc` so that `x` is not increased by `1` after the execution of the function body then the program will terminate with an error message similar to the following (so it will be evident that the bug is in `inc` body): +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. @@ -44,7 +44,7 @@ In real code, function bodies are rarely this simple and can hide bugs that make 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 above to the standard error `std::cerr` and terminates the program calling `std::terminate` (but this behaviour can be customized to take any user-specified action including throwing exceptions, see __Throw_on_Failure__). +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. [footnote *Rationale:* @@ -52,14 +52,14 @@ 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 having to manually program a significant amount of boiler-plate code (see __No_Lambda_Functions__). +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__). ] 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. -These can check class invariants and can also /subcontract/ inheriting and extending contracts for derived classes (see also [@../../example/features/introduction_public.cpp =introduction_public.cpp=] and __Public_Function_Overrides__): +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 here just to exercise subcontracting, it is somewhat arbitrary and it would likely not appear in real production code. +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. ] [import ../example/features/introduction_public.cpp] @@ -68,13 +68,13 @@ The `pushable` base class is used here just to exercise subcontracting, it is so [heading Language Support] The authors of this library advocate for contracts to be added to the core language. -Adding contract programming to the C++ standard has a number of advantages over any library implementation (shorter and more concise syntax to program contracts, specify contracts in declarations instead of definitions, enforce contract constant-correctness, expected faster compile and run times, vendors could develop static analysis tools to recognize and check contracts statically when possible, compiler optimization could be improved based on contract conditions, etc.). +Adding contract programming to the C++ standard has a number of advantages over any library implementation (shorter and more concise syntax to program contracts, specify contracts in declarations instead of definitions, enforce contract constant-correctness, expected faster compile- and run-time, vendors could develop static analysis tools to recognize and check contracts statically when possible, compiler optimizations could be improved based on contract conditions, etc.). -Unfortunately, detailed and complete proposals to add contracts to the C++ standard such as __N1962__ were rejected by the C++ standard committee and it is not clear if the current proposal for adding contracts to C++ __P0380R1__ will actually be accepted by the standard. +Unfortunately, detailed and complete proposals to add contracts to the C++ standard such as __N1962__ were rejected by the C++ standard committee and it is not clear if the current proposal for adding contracts to C++ __P0380__ will actually be accepted by the standard. [footnote -The authors find attractive the idea of using C++ attributes to specify contracts as indicated in __P0380R1__. +The authors find attractive the syntax that uses C++11 attributes `[[...]]` to specify contracts as indicated in __P0380__. ] -In any case, __P0380R1__ 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 also __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 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). [endsect] diff --git a/doc/main.qbk b/doc/main.qbk index a095994..c65dbcd 100644 --- a/doc/main.qbk +++ b/doc/main.qbk @@ -8,7 +8,7 @@ [quickbook 1.5] [version 1.0] [authors [Caminiti lorcaminiti@gmail.com, Lorenzo]] - [copyright 2008-2016 Lorenzo Caminiti] + [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])] ] @@ -74,7 +74,7 @@ [def __Volatile_Public_Functions__ [link boost_contract.extras.volatile_public_functions Volatile Public Functions]] [def __Move_Operations__ [link boost_contract.extras.move_operations Move Operations]] [def __Unions__ [link boost_contract.extras.unions Unions]] -[def __Disable_Contract_Checking__ [link boost_contract.extras.disable_contract_checking Disable Contract Checking]] +[def __Disable_Contract_Checking__ [link boost_contract.extras.disable_contract_checking__and_assertion_levels_ Disable Contract Checking]] [def __Disable_Contract_Checking_and_Assertion_Levels__ [link boost_contract.extras.disable_contract_checking__and_assertion_levels_ Disable Contract Checking (and Assertion Levels)]] [def __Disable_Contract_Compilation__ [link boost_contract.extras.disable_contract_compilation__macro_interface_ Disable Contract Compilation]] [def __Disable_Contract_Compilation_Macro_Interface__ [link boost_contract.extras.disable_contract_compilation__macro_interface_ Disable Contract Compilation (Macro Interface)]] @@ -130,11 +130,11 @@ 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 an exception), optional compilation of assertions, disable assertions while already checking other assertions (to avoid infinite recursion), etc. (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__). [note In one of its previous revisions, this library passed Boost formal review and it was accepted into the Boost libraries (see [@https://groups.google.com/forum/?fromgroups=#!topic/boost-list/jQ7OjAmos_Y]). -However, the authors have not had time yet to add this library to a Boost release. +However, the authors have not had time to add this library to a Boost release yet. ] This library source is hosted at [@https://github.com/lcaminiti/boost-contract]. diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 7cf0ee3..ba4eb47 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -6,12 +6,12 @@ [section Tutorial] -This section illustrates basic uses of this library. +This section is a guide to basic usages of this library. [section Non-Member Functions] Contracts for non-member functions are programmed using [funcref boost::contract::function]. -For example (see also [@../../example/features/non_member.cpp =non_member.cpp=]): +For example (see [@../../example/features/non_member.cpp =non_member.cpp=]): [import ../example/features/non_member.cpp] [non_member] @@ -21,19 +21,19 @@ Alternatively, programmers can selectively include only the header files they ac It is possible to specify preconditions, postconditions, and exception guarantees for non-member functions (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). -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 also [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). +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. ] +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 In some cases, it might be necessary to program some code before the contract. -For example for acquiring resources that will be used while checking the contract like old values, but also to lock mutexes (or other synchronization mechanisms) in multi-threaded programs (as usual with C++, in these cases it is generally preferred to use RAII objects to automatically control acquisition and release of the resources). +For example for acquiring resources that will be used while checking the contract like old values, but also to lock mutexes (or other synchronization mechanisms) in multi-threaded programs. ] -At construction, the RAII object does the following (enclosing function entry): +At construction, the [classref boost::contract::check] RAII object for non-member functions does the following (enclosing function entry): # Check preconditions, by calling the nullary functor [^['r]]`()` passed to `.precondition(`[^['r]]`)`. @@ -45,7 +45,7 @@ At destruction instead (enclosing function exit): # Check exception guarantees, by calling the nullary functor [^['e]]`()` passed to `.except(`[^['e]]`)`. This ensures that non-member function contracts are correctly checked at run-time (see __Function_Calls__). -(Also note that functions will correctly check their contracts even when they are called via function pointers or function objects.) +(Also note that functions will correctly check their contracts even when they are called via function pointers, function objects, etc.) [note A non-member function can avoid calling [funcref boost::contract::function] for efficiency but only when it has no preconditions, no postconditions, and no exception guarantees. @@ -55,16 +55,16 @@ A non-member function can avoid calling [funcref boost::contract::function] for [section Preconditions] -When preconditions are specified, they are programmed using a functor [^['r]] passed to `.precondition(`[^['r]]`)` that can be called with no parameter [^['r]]`()`. +When preconditions are specified, they are programmed using a functor [^['r]] passed to `.precondition(`[^['r]]`)` that can be called with no parameters as [^['r]]`()`. Contracts that do not have preconditions simply do not call `.precondition(...)`. -When they are all specified, preconditions must appear before postconditions and exception guarantees (see __Postconditions__ and __Exception_Guarantees__). +Preconditions must appear before postconditions and exception guarantees when these are all present (see __Postconditions__ and __Exception_Guarantees__). C++11 lambda functions are convenient to program preconditions, but any other nullary functor can be used (see __No_Lambda_Functions__). [footnote 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): +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__): boost::contract::check c = boost::contract::function() // Same for all other contracts. .precondition([&] { // Capture by reference or value... @@ -75,32 +75,35 @@ For example, for [funcref boost::contract::function] (same for public functions, ; 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 (but in this documentation preconditions often capture these variables by reference to avoid such overhead). +These variables can be captured by value when the overhead of copying such variables is acceptable. +[footnote +In this documentation preconditions often capture variables by reference to avoid extra copies. +] 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__): BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition contains commas `,` not already within parenthesis `(...)`... + // Or, if boolean-condition contains commas `,` not already within parenthesis `()`... BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. -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 also if calling the functor specified via `.precondition(...)` 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::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.). [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 member 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). - -This library leaves it up to the programmers to only use public members when programming contracts, and especially when programming preconditions (see __Specification_vs_Implementation__). +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__). ] [endsect] [section Postconditions] -When postconditions are specified, they are programmed using a functor [^['s]] passed to `.postcondition(`[^['s]]`)` that can be called with no parameter [^['s]]`()`. +When postconditions are specified, they are programmed using a functor [^['s]] passed to `.postcondition(`[^['s]]`)` that can be called with no parameters as [^['s]]`()`. Contracts that do not have postconditions simply do not call `.postcondition(...)`. -When they are all specified, postconditions must appear after preconditions but before exception guarantees (see __Preconditions__ and __Exception_Guarantees__). +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): @@ -120,15 +123,16 @@ Postconditions can also capture return and old values (see __Return_Value__ and 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 also __No_Macros__): +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__): BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `(...)`... + // Or, if boolean-condition has commas `,` not already within parenthesis `()`... BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. -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 also if calling the functor specified via `.postcondition(...)` 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::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.). -For non-void virtual and overriding public member functions, 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]]`)` (so to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). +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] @@ -160,21 +164,21 @@ The functor used to program postconditions should capture the result variable by 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 (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 declaring the result variable (see __Optional_Return_Value__). -Non-void virtual and overriding public member functions must always declare and use a result variable even when postconditions do not directly use the function return value (so to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). +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__). [endsect] [section Old Values] -When old values are used in postconditions or in exception guarantees, programmes are responsible to declare local variables before the contract and to assign them to related old value expressions using [macroref BOOST_CONTRACT_OLD]. +When old values are used in postconditions or in exception guarantees, programmes are responsible to declare local variables before the contract and to assign them to related old value expressions using [macroref BOOST_CONTRACT_OLDOF]. [footnote -The name of a local variable that holds an old value is arbitrary, but [^old_['name]] is often used in this documentation. +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): - boost::contract::old_ptr<``/type/``> old_``/name/`` = BOOST_CONTRACT_OLD(``/expression/``); + 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... @@ -187,21 +191,24 @@ For example, for [funcref boost::contract::function] (but same for all other con }) ; -Old values are handled by this library using the smart pointer class template [classref boost::contract::old_ptr] (so programmers do not directly manage the allocation and deallocation of the pointed memory). +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). ] -The pointed old value is automatically qualified as `const` (so old values cannot be mistakenly changed by the 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 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). -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 (for example, 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, etc.). -Furthermore, see __Old_Values_at_Body__ for delaying the assignment of old values until after class invariants (for constructors, destructors, and public member 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). +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. +] +See __Old_Values_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). -[macroref BOOST_CONTRACT_OLD] is a variadic macro and it takes an extra parameter when used in virtual or overriding public functions (see __Virtual_Public_Functions__ and __Public_Function_Overrides__). -C++11 auto declarations can be used with [macroref BOOST_CONTRACT_OLD] for brevity `auto `[^old_['name] = BOOST_CONTRACT_OLD(['expression])]. -See __No_Macros__ to program old values without using [macroref BOOST_CONTRACT_OLD] (e.g., on compilers that do not support variadic macros). +[macroref BOOST_CONTRACT_OLDOF] is a variadic macro and it takes an extra parameter when used in virtual public functions or public function overrides (see __Virtual_Public_Functions__ and __Public_Function_Overrides__). +C++11 auto declarations can be used with [macroref BOOST_CONTRACT_OLDOF] for brevity `auto `[^old_['variable-name] = BOOST_CONTRACT_OLDOF(['expression])]. +See __No_Macros__ to program old values without using [macroref BOOST_CONTRACT_OLDOF] (e.g., on compilers that do not support variadic macros). [note This library ensures that old values are copied only once. @@ -212,9 +219,9 @@ This library also ensures that old values are never copied when postconditions a [section Exception Guarantees] -When exception guarantees are specified, they are programmed using a functor [^['e]] passed to `.except(`[^['e]]`)` that can be called with no parameter [^['e]]`()`. +When exception guarantees are specified, they are programmed using a functor [^['e]] passed to `.except(`[^['e]]`)` that can be called with no parameters as [^['e]]`()`. Contracts that do not have exception guarantees simply do not call `.except(...)`. -When they are all specified, exception guarantees must appear after both preconditions and postconditions (see __Preconditions__ and __Postconditions__). +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): @@ -227,32 +234,31 @@ For example, for [funcref boost::contract::function] (but same for all other con }) ; -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 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__). - -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). +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). +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 practise (and they are not used in most of the examples listed in the rest of this documentation). +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. ] -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 also __No_Macros__): +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__): BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `(...)`... + // Or, if boolean-condition has commas `,` not already within parenthesis `()`... BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. -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 also if calling the functor specified via `.except(...)` throws an exception (by default, this handler prints an error message to `std::cerr` and terminates the program calling `std::terminate`). +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). [important -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. -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 this library to check the exception guarantees in the first place). - -Therefore, programmers are strongly advised to not change the exception-guarantee failure handler to throw exceptions instead of terminating the program. +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. +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. ] [endsect] @@ -260,9 +266,9 @@ Therefore, programmers are strongly advised to not change the exception-guarante [section Class Invariants] When class invariants are specified, they are programmed in a public `const` member function named `invariant` taking no argument and returning `void`. -Classes that do not have invariants, simply do not declare the `invariant` member function. +Classes that do not have invariants, simply do not declare this `invariant` member function. [footnote -This library uses template meta-programming (SFINAE-based introspection techniques) to check invariants only for classes that declare a member function named `invariant`. +This library uses template meta-programming (SFINAE-based introspection techniques) to check invariants only for classes that declare a member function named [macroref BOOST_CONTRACT_INVARIANT_FUNC]. ] For example: @@ -277,16 +283,17 @@ For example: }; This member function must be `const` because contracts should not modify the object state (see __Constant_Correctness__). -This library will generate a compile-time error if the `const` qualifier is missing (unless the [macroref BOOST_CONTRACT_PERMISSIVE] macro is defined). +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 also __No_Macros__): +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__): BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if boolean-condition has commas `,` not already within parenthesis `(...)`... + // Or, if boolean-condition has commas `,` not already within parenthesis `()`... BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. -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 also if the `invariant` function throws an exception (by default, these handlers print an error message to `std::cerr` and terminate 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 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.). See __Access_Specifiers__ to avoid making the `invariant` member function `public`. [footnote @@ -296,16 +303,18 @@ However, in production code it might not be acceptable to augment the public mem See [macroref BOOST_CONTRACT_INVARIANT_FUNC] to use a name different from `invariant` (e.g., because `invariant` clashes with other names in user-defined classes). [note -Contract assertion is checked (not event class invariants) when a data member is 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 member functions (e.g., setters and getters) that can check the class invariants. +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. ] +See __Volatile_Public_Functions__ to program invariants for classes with `volatile` public functions. + [heading Static Class Invariants] -When static class invariants are specified, they are programmed in a public `static` member functions named `static_invariant` taking no argument and returning `void`. +When static class invariants are specified, they are programmed in a public `static` member function named `static_invariant` taking no argument and returning `void`. Classes that do not have static class invariants, simply do not declare a `static_invariant` member function. [footnote -This library uses template meta-programming (SFINAE-based introspection techniques) to check static invariants only for classes that declare a member function named `static_invariant`. +This library uses template meta-programming (SFINAE-based introspection techniques) to check static invariants only for classes that declare a member function named [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC]. ] For example: @@ -323,54 +332,53 @@ 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 also __No_Macros__): +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__): BOOST_CONTRACT_ASSERT(``/boolean-condition/``) - // Or, if condition has commas `,` not already within parenthesis `(...)`... + // Or, if condition has commas `,` not already within parenthesis `()`... BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) // ...use extra parenthesis. -This library will automatically call the 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 also if the `static_invariant` function throws an exception (by default, these handlers print an error message to `std::cerr` and terminate 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 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.). See __Access_Specifiers__ to avoid making `static_invariant` member function `public`. [footnote In this documentation the `static_invariant` member function is often declared `public` for simplicity. However, in production code it might not be acceptable to augment the public members of a class adding the `static_invariant` function (and that can be avoided using [classref boost::contract::access] as explained in __Access_Specifiers__). ] -Set [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC] to use a name different from `static_invariant` (e.g., because `static_invariant` clashes with other names in user-defined classes). +See [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC] to use a name different from `static_invariant` (e.g., because `static_invariant` clashes with other names in user-defined classes). [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]). ] -Finally, see __Volatile_Class_Invariants__ to program invariants for classes with volatile public member functions. - [endsect] [section Constructors] -Contracts for constructors are programmed using [funcref boost::contract::constructor] and the [classref boost::contract::constructor_precondition] base class. -For example (see also [@../../example/features/public.cpp =public.cpp=]): +Contracts for constructors are programmed using the [funcref boost::contract::constructor] function and the [classref boost::contract::constructor_precondition] base class. +For example (see [@../../example/features/public.cpp =public.cpp=]): [import ../example/features/public.cpp] [public_class_begin] [public_constructor] [public_class_end] -It is not possible to specify preconditions using `.precondition(...)` for constructors (the library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]). +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]). -Programmes should not access the object `this` from constructor preconditions (because the object does not exists yet before the constructor body is executed). +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 at compile-time (not recommended). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still 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: [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. +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 or data member). +* 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). [footnote @@ -385,16 +393,17 @@ A class can avoid inheriting from [classref boost::contract::constructor_precond ] 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). +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 at compile-time (not recommended). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still 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). +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). The constructor body is programmed right after the declaration of the RAII object. -At construction, the RAII object does the following (enclosing constructor entry): + +At construction, the [classref boost::contract::check] RAII object for constructors does the following (enclosing constructor entry): # Check static class invariants, by calling [^['type-of]]`(*this)::static_invariant()` (but not non-static class invariants because the object does not exist yet). @@ -410,22 +419,21 @@ At destruction instead (enclosing constructor exit): This together with C++ object construction mechanism of base classes and the use of [classref boost::contract::constructor_precondition] ensures that the constructor contracts are correctly checked at run-time (see __Constructor_Calls__). [note -A constructor can avoid calling [funcref boost::contract::constructor] for efficiency but only when it has no postconditions, no exception guarantees, and its class has no invariants. -(Even if [funcref boost::contract::constructor] is not used by a derived class, contracts of base class constructors will still be correctly checked by C++ object construction mechanism.) +A constructor can avoid calling [funcref boost::contract::constructor] for efficiency but only when it has no postconditions, no exception guarantees, and its class has no invariants (even if [funcref boost::contract::constructor] is not used by a derived class, contracts of base class constructors will still be correctly checked by C++ object construction mechanism). 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 operations automatically generated by C++ (move constructor, etc.). +Similar considerations apply to all other constructors automatically generated by C++ (e.g., 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 technically 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 (see __Private_and_Protected_Functions__). +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 { protected: // Contract for a protected constructor (same for private constructors). - a() : + a() : // Still use this base class to check constructor preconditions. boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(...); ... @@ -438,9 +446,13 @@ For example: BOOST_CONTRACT_ASSERT(...); ... }) + .except([&] { + BOOST_CONTRACT_ASSERT(...); + ... + }) ; - ... // Body. + ... // Constructor body. } ... @@ -451,24 +463,25 @@ For example: [section Destructors] Contracts for destructors are programmed using [funcref boost::contract::destructor]. -For example (see also [@../../example/features/public.cpp =public.cpp=]): +For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_begin] [public_destructor] [public_class_end] -It is not possible to specify preconditions for destructors (the 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 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). +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 at compile-time (not recommended). +See __No_Lambda_Functions__ to enforce this constraint at compile-time (but still not recommended because of extra boiler-plate code). ] 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). +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). The destructor body is programmed right after the declaration of the RAII object. -At construction, the RAII object does the following (enclosing destructor entry): + +At construction, the [classref boost::contract::check] RAII object for destructors does the following (enclosing destructor entry): # Check static and non-static class invariants, by calling ['[^type-of]]`(*this)::static_invariant()` __AND__ `this->invariant()`. @@ -484,15 +497,14 @@ At destruction instead (enclosing destructor exit): This together with C++ object destruction mechanism of base classes ensures that destructor contracts are correctly checked at run-time (see __Destructor_Calls__). [note -A destructor can avoid calling [funcref boost::contract::destructor] for efficiency but only when it has no postconditions, no exception guarantees, and its class has no invariants. -(Even if [funcref boost::contract::destructor] is not used by a derived class, contracts of base class destructors will still be correctly checked by C++ object destruction mechanism.) +A destructor can avoid calling [funcref boost::contract::destructor] for efficiency but only when it has no postconditions, no exception guarantees, and its class has no invariants (even if [funcref boost::contract::destructor] is not used by a derived class, contracts of base class destructors will still be correctly checked by C++ object destruction mechanism). The default destructor automatically generated by C++ will not check contracts. Therefore, unless the destructor is not public or it has no postconditions, no exception guarantees, and its class has no invariants, programmers should manually define it using [funcref boost::contract::destructor]. ] -Private and protected destructors can omit [funcref boost::contract::destructor] (because they are not part of the public interface of the class so they are technically not required to check class invariants, see __Destructor_Calls__). -They could use [funcref boost::contract::function] (but not [funcref boost::contract::destructor]) to only check postconditions and exception guarantees without checking class invariants (see __Private_and_Protected_Functions__). +Private and protected destructors can omit [funcref boost::contract::destructor] (because they are not part of the public interface of the class so they are not required to check class invariants, see __Destructor_Calls__). +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 { @@ -508,7 +520,7 @@ For example: }) ; - ... // Body. + ... // Destructor body. } ... @@ -518,21 +530,22 @@ For example: [section Public Functions] -Contracts for public member functions are programmed using [funcref boost::contract::public_function]. -In this section, let's consider public member functions that are not static, not virtual, and do not override any function from base classes. -For example (see also [@../../example/features/public.cpp =public.cpp=]): +Contracts for public functions are programmed using [funcref boost::contract::public_function]. +In this section, let's consider public functions that are not static, not virtual, and do not override any function from base classes. +For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_begin] [public_function] [public_class_end] -It is possible to specify preconditions, postconditions, and exception guarantees for public member functions (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). -The [funcref boost::contract::public_function] function takes `this` as a parameter (because public member functions check class invariants, see __Class_Invariants__). +It is possible to specify preconditions, postconditions, and exception guarantees for public functions (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). +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). +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). -The public member function body is programmed right after the declaration of the RAII object. -At construction, the RAII object does the following (enclosing public function entry): +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): # Check static and non-static class invariants, by calling [^['type-of]]`(*this)::static_invariant()` __AND__ `this->invariant()`. # Check preconditions, by calling the nullary functor [^['r]]`()` passed to `.precondition(`[^['r]]`)`. @@ -545,10 +558,10 @@ At destruction instead (enclosing public function exit): # Else: # Check exception guarantees, by calling the nullary functor [^['e]]`()` passed to `.except(`[^['e]]`)`. -This ensures that public member function contracts are correctly checked at run-time (see __Public_Function_Calls__). +This ensures that public function contracts are correctly checked at run-time (see __Public_Function_Calls__). [note -A public member function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions, no postconditions, no exception guarantees, it is not virtual, it does not override any virtual function, and its class has no invariants. +A public function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions, no postconditions, no exception guarantees, it is not virtual, it does not override any virtual function, and its class has no invariants. 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]. @@ -559,60 +572,76 @@ Similar considerations apply to all other operations automatically generated by [section Virtual Public Functions] -Contracts for public member functions are programmed using [funcref boost::contract::public_function]. -In this section, let's consider public member functions that are virtual but that still do not override any function from base classes. -For example (see also [@../../example/features/public.cpp =public.cpp=]): +Contracts for public functions are programmed using [funcref boost::contract::public_function]. +In this section, let's consider public functions that are virtual but that do not override any function from base classes. +For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_begin] [public_virtual_function] [public_class_end] -Public virtual functions must declare an extra trailing parameter of type [classref boost::contract::virtual_]`*` with default value `0` (i.e., `nullptr`). +Virtual public functions must declare an extra trailing parameter of type [classref boost::contract::virtual_]`*` with default value `0` (i.e., `nullptr`). [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 as a function pointer, for function pointer type-casts, etc.). -Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLD] and [funcref boost::contract::public_function] calls in the virtual function definition. +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.). +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:* -The [classref boost::contract::virtual_]`*` optional parameter is used by this library to determine that a function is virtual (in C++ it is not possible to introspect if a function is declared `virtual`). -Furthermore, this parameter is internally used by this library to pass result and old values that are evaluated by the overriding function to overridden virtual functions in base classes, and also to check preconditions, postconditions, and exception guarantees of overridden virtual functions when subcontracting (but without executing overridden function bodies). +The [classref boost::contract::virtual_]`*` parameter is used by this library to determine that a function is virtual (in C++ it is not possible to introspect if a function is declared `virtual`). +Furthermore, this parameter is internally used by this library to pass result and old values that are evaluated by the overriding function to overridden virtual functions in base classes, and also to check preconditions, postconditions, and exception guarantees of overridden virtual functions to implement subcontracting. ] -The [funcref boost::contract::public_function] function takes `this` as a parameter (because public virtual functions check class invariants, see __Class_Invariants__). +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`: -As shown in the example above, when the public virtual function has a non-void return type programmers must pass a reference to the function return value as the second argument of [funcref boost::contract::public_function]. -In this case, this library will pass the return value to the postcondition functor (that must therefore take one single argument matching the return type, possibly as a constant reference `const&` to avoid extra copies of the return value). + // 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([&] { ... }) + ; + +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): [footnote *Rationale:* -The functor passed to `.postcondition(...)` takes the extra return value parameter because that is used by this library to pass the return value evaluated by the overriding function to all its overridden virtual functions when subcontracting. +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. ] -Therefore, postconditions are checked by calling the nullary functor [^['s]]`()` passed to `.postcondition(`[^['s]]`)` for void public virtual functions, or the unary functor [^['s]]`(`[^['result]]`)` for non-void public virtual functions. + + // 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([&] { ... }) + ; [important -It is the responsibility of the programmers to pass the extra parameter `v` to all [macroref BOOST_CONTRACT_OLD] and [funcref boost::contract::public_function] calls within public virtual functions, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void public virtual functions. -This library cannot automatically generate compile-time errors if programmers fail to do so (but in general this will cause the library to not correctly check contracts at run-time). +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. +This library cannot automatically 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). [footnote *Rationale:* -This library does not require the function type when using [funcref boost::contract::public_function] for non-overriding virtual functions. -Therefore, this library does not know if the enclosing function has a non-void return type so it cannot check if the return value reference is passed as required for non-overriding virtual functions. -Instead this library requires the function type for overriding virtual functions thus it gives a compile-time error if the return value reference is missing in those cases. +This library does not require programmers to specify the function type when using [funcref boost::contract::public_function] for non-overriding virtual public functions. +Therefore, this library does not know if the enclosing function has a non-void return type so it cannot check if the return value reference is passed as required for non-overriding virtual public functions. +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. +] +Remember: +[:Always pass the function parameter `v` as the first argument to [macroref BOOST_CONTRACT_OLDOF] and to [funcref boost::contract::public_function].] +[:Always pass the function return value to [funcref boost::contract::public_function] right after `v` (for non-void virtual public functions).] ] -Remember: Always pass `v` as the first argument to old value macros, the contract, etc. for public virtual functions, and always pass the result variable after `v` to the contract for non-void public virtual functions. -] - -For the rest, the same considerations made in __Public_Functions__ apply to public virtual functions as well. +For the rest, considerations made in __Public_Functions__ apply to virtual public functions as well. [endsect] [section Public Function Overrides (Subcontracting)] -Contracts for public member functions are programmed using [funcref boost::contract::public_function]. -In this section, let's consider public member functions (virtual or not) that override public virtual functions from one or more public base classes. -For example (see also [@../../example/features/public.cpp =public.cpp=]): +Contracts for public functions are programmed using [funcref boost::contract::public_function]. +In this section, let's consider public functions (virtual or not) that override virtual public functions from one or more public base classes. +For example (see [@../../example/features/public.cpp =public.cpp=]): [footnote -In this documentation, overriding functions are often marked with the code comment `/* override */`. +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). ] @@ -620,50 +649,74 @@ On compilers that support C++11 virtual specifiers, the `override` identifier ca [public_function_override] [public_derived_class_end] -The extra `typedef` that uses [macroref BOOST_CONTRACT_BASE_TYPES] is required by this library for derived classes and it is internally used detect base classes for subcontracting (see __Base_Classes__). +The extra `typedef` declared using [macroref BOOST_CONTRACT_BASE_TYPES] is required by this library for derived classes and it is internally used detect base classes for subcontracting (see __Base_Classes__). -When called from overriding public functions, the [funcref boost::contract::public_function] function template takes an explicit template argument `override_`[^['function-name]] that must be defined by: +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]``) -This can be used 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 __Overloaded_Functions__). +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_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__). -This library will generate a compile-time error if there is no suitable virtual function to override in any of the public base classes for subcontracting. -[footnote -This compile-time error generated by the library is similar in principle to the error generated by the C++11 `override` specifier, but it is limited to functions with the extra [classref boost::contract::virtual_]`*` parameter and searched recursively only in `public` base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES] because only those are valid functions to override for subcontracting. -] - 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 number of functions): +For example, for three functions named `f`, `g`, and `h` (but same for any other number of functions), the following: BOOST_CONTRACT_OVERRIDES(f, g, h) -The above is equivalent to: +Is equivalent to: +[footnote +This library does not provider an equivalent of [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that operates on multiple function names at once (simply because programmers will probably not use [macroref BOOST_CONTRACT_NAMED_OVERRIDE] often in the first place). +] BOOST_CONTRACT_OVERRIDE(f) BOOST_CONTRACT_OVERRIDE(g) BOOST_CONTRACT_OVERRIDE(h) -(However, note that there is not an equivalent to [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that operates on multiple function names at once.) +This library will generate a compile-time error if there is no suitable virtual function to override in any of the public base classes for subcontracting. +[footnote +The compile-time error generated by the library in this case is similar in principle to the error generated by the C++11 `override` specifier, but it is limited to functions with the extra [classref boost::contract::virtual_]`*` parameter and searched recursively only in `public` base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES] because only those are considered for subcontracting. +] Public function overrides must always list the extra trailing parameter of type [classref boost::contract::virtual_]`*` with default value `0` (i.e., `nullptr`), even when they are not declared `virtual` (because this parameter is present in the signature of the virtual function being overridden from base classes). -Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLD] and [funcref boost::contract::public_function] calls in the function override definition (see __Virtual_Public_Functions__). +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 public function override definition (see __Virtual_Public_Functions__). -When called from a public function override, [funcref boost::contract::public_function] also 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. +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 function pointer and references to all function arguments are needed for overriding virtual public functions 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). +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`: -As shown in the example above, when the overriding public function has a non-void return type programmers must pass a reference to the function return value as the second argument of [funcref boost::contract::public_function] (this library will generate a compile-time error otherwise). + // 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([&] { ... }) + ; + +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 public virtual functions, also overriding functions use the extra return value parameter to pass it to the overridden functions when subcontracting. -In the case of overriding functions 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 public virtual functions because their contracts do not take the function pointer as a parameter, see __Virtual_Public_Functions__). +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 this case, this library will pass the return value to the postcondition functor (that must therefore take one single argument matching the return type, possibly as a constant reference `const&` to avoid extra copies of the return value). +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([&] { ... }) + ; + 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 *Rationale:* @@ -671,13 +724,14 @@ The `boost::bad_any_cast` exception could not used here because it does not prin ] [important -It is the responsibility of the programmers to pass the extra parameter `v` to all [macroref BOOST_CONTRACT_OLD] and [funcref boost::contract::public_function] calls within overriding public functions, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void overriding public functions. -This library cannot always generate compile-time errors if programmers fail to do so (but in general this will cause the library to not correctly check contracts at run-time). - -Remember: Always pass `v` as the first argument to old value macros, the contract, etc. for public function overrides, and always pass the result variable after `v` to the contract for non-void public function overrides. +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). +Remember: +[:Always pass the function parameter `v` as the first argument to [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function].] +[:Always pass the function return value to [funcref boost::contract::public_function] right after `v` (for non-void public function overrides).] ] -At construction, the RAII object returned by the [funcref boost::contract::public_function]`<...>` function does the following (enclosing public function override entry): +At construction, the [classref boost::contract::check] RAII object for public function overrides does the following (enclosing public function override entry): # Check static and non-static class invariants for all overridden bases and for the derived class in __AND__ with each other, by calling [^['type-of](['overridden-base_1])]`::static_invariant()` __AND__ [^['overridden-base_1]]`.invariant()` __AND__... [^['type-of](['overridden-base_n])]`::static_invariant()` __AND__ [^['overridden-base_n]]`.invariant()` __AND__ [^['type-of]]`(*this)::static_invariant()` __AND__ `this->invariant()`. # Check preconditions for all overridden base functions and for the overriding derived function in __OR__ with each other, by calling the nullary functors [^['r_1]]`()` __OR__... [^['r_n]]`()` __OR__ [^['r]]`()` passed to `.precondition(`[^['r_1]]`)`, ... `.precondition(`[^['r_n]]`)`, `.precondition(`[^['r]]`)` for all of the overridden and overriding functions respectively. @@ -690,16 +744,16 @@ At destruction instead (enclosing public function override exit): # Else: # Check exception guarantees for all overridden base functions and for the overriding derived function in __AND__ with each other, by calling the nullary functors [^['e_1]]`()` __AND__... [^['e_n]]`()` __AND__ [^['e]]`()` passed to `.except(`[^['e_1]]`)`, ... `.except(`[^['e_n]]`)`, `.except(`[^['e]]`)` for all of the overridden and overriding functions respectively. -This ensures that subcontracts of public function overrides are checked correctly at run-time (see __Public_Function_Calls__). +This ensures that public function override contracts and subcontracts are correctly checked at run-time (see __Public_Function_Calls__). -For the rest, the same considerations made in __Virtual_Public_Functions__ apply to public function overrides as well. +For the rest, considerations made in __Virtual_Public_Functions__ apply to public function overrides as well. [endsect] [section Base Classes (Subcontracting)] In order for this library to support subcontracting, programmers must specify the bases of a derived class declaring a public member type named `base_types` via a `typedef` using [macroref BOOST_CONTRACT_BASE_TYPES]. -For example (see also [@../../example/features/base_types.cpp =base_types.cpp=]): +For example (see [@../../example/features/base_types.cpp =base_types.cpp=]): [import ../example/features/base_types.cpp] [base_types] @@ -711,18 +765,19 @@ The name of this local macro is arbitrary, but `BASES` is often used in this doc ] [macroref BOOST_CONTRACT_BASE_TYPES] is a variadic macro and accepts a list of bases separated by commas (see __No_Macros__ to program `base_types` without using macros). -As already noted in __Constructors__, when the extra base [classref boost::contract::constructor_precondition] is used to program constructor preconditions, it must always be private and appear as the very first base. +As already noted in __Constructors__, when the extra base [classref boost::contract::constructor_precondition] is used to program constructor preconditions, its inheritance access level must always be `private` and it must be specified as the very first base. [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++). [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 to be for subcontracting (i.e., from `base_types`). +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`). ] -This library will generate a compiler-error if the first base is missing its inheritance access level, but this library will not be able to error if the access level is missing from bases after the first one. - +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). +Remember: +[:Always explicitly specify the inheritance access level `public`, `protected`, or `private` for base classes of derived classes with contracts.] ] See __Access_Specifiers__ to avoid making the `base_types` member type `public`. @@ -730,31 +785,34 @@ See __Access_Specifiers__ to avoid making the `base_types` member type `public`. In this documentation the `base_type` member type is often declared `public` for simplicity. However, in production code it might not be acceptable to augment the public members of a class adding the `base_types` type (and that can be avoided using [classref boost::contract::access] as explained in __Access_Specifiers__). ] -See [macroref BOOST_CONTRACT_BASE_TYPEDEF] to use a name different from `base_types` (e.g., because `base_types` clashes with other names in user-defined classes). +See [macroref BOOST_CONTRACT_BASES_TYPEDEF] to use a name different from `base_types` (e.g., because `base_types` clashes with other names in user-defined classes). [endsect] [section Static Public Functions] -Contracts for public member functions are programmed using [funcref boost::contract::public_function]. -In this section, let's consider static public member functions. -For example (see also [@../../example/features/static_public.cpp =static_public.cpp=]): +Contracts for public functions are programmed using [funcref boost::contract::public_function]. +In this section, let's consider static public functions. +For example (see [@../../example/features/static_public.cpp =static_public.cpp=]): [import ../example/features/static_public.cpp] [static_public] -It is possible to specify preconditions, postconditions, and exception guarantees for static public member 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 that type is necessary to check static class invariants, see __Static_Class_Invariants__): +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__): - // Contract declaration for a static public function (explicit class-type). - boost::contract::check c = boost::contract::public_function<``[^['class-type]]``>() - ... // Preconditions, postconditions, exception guarantees, etc. + // In a static public function. + boost::contract::check c = boost::contract::public_function<``[^['class-type]]``>() // Explicit class type 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). +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). -The static public member functions body is programmed right after the declaration of the RAII object. -At construction, the RAII object does the following (enclosing static public function entry): +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): # Check static class invariants, by calling [^['class-type]]`::static_invariant()` (but never non-static class invariants). # Check preconditions, by calling the nullary functor [^['r]]`()` passed to `.precondition(`[^['r]]`)`. @@ -767,13 +825,13 @@ 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 member function contracts are correctly checked at run-time (see __Public_Function_Calls__). +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 no inheritance. +Note that static public functions do not subcontract because they have no object `this` and therefore there is no inheritance. ] [note -A static public member 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). +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). ] [endsect] diff --git a/example/features/check.cpp b/example/features/check.cpp index 251d51c..65b30f0 100644 --- a/example/features/check.cpp +++ b/example/features/check.cpp @@ -36,7 +36,7 @@ int main() { //] //[check_macro - // Implementation checks via macro (preferred). + // Implementation checks via macro (disable run- and compile-time overhead). BOOST_CONTRACT_CHECK(gcd(12, 28) == 4); BOOST_CONTRACT_CHECK(gcd(4, 14) == 2); //] diff --git a/example/features/code_block.cpp b/example/features/code_block.cpp index 222dc0a..859f5a5 100644 --- a/example/features/code_block.cpp +++ b/example/features/code_block.cpp @@ -12,8 +12,9 @@ int main() { int total = 10; //[code_block - { - // Contract for a code block. + /* ... */ + // Contract for a code block. + { // Code block entry (check preconditions). boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() .precondition([&] { @@ -25,7 +26,8 @@ int main() { ; total += v[0] + v[1] + v[2]; // Code block body. - } + } // Code block exit (check postconditions and exceptions guarantees). + /* ... */ //] assert(total == 16); diff --git a/example/features/friend.cpp b/example/features/friend.cpp index 99415f3..e5c3730 100644 --- a/example/features/friend.cpp +++ b/example/features/friend.cpp @@ -3,25 +3,9 @@ #include #include -//[friend_byte -class bytes; - -class byte { - friend bool operator==(bytes const& left, byte const& right); - -private: - char value_; - - /* ... */ -//] - -public: - // Could program invariants and contracts for following too. - explicit byte(char value) : value_(value) {} - bool empty() const { return value_ == '\0'; } -}; - //[friend_bytes +class byte; + class bytes { // Friend functions are not member functions... friend bool operator==(bytes const& left, byte const& right) { @@ -51,6 +35,22 @@ public: bool empty() const { return values_ == ""; } }; +//[friend_byte +class byte { + friend bool operator==(bytes const& left, byte const& right); + +private: + char value_; + + /* ... */ +//] + +public: + // Could program invariants and contracts for following too. + explicit byte(char value) : value_(value) {} + bool empty() const { return value_ == '\0'; } +}; + int main() { bytes p("aaa"); byte a('a'); diff --git a/example/features/ifdef_audit.cpp b/example/features/ifdef_audit.cpp index ba3458f..731f640 100644 --- a/example/features/ifdef_audit.cpp +++ b/example/features/ifdef_audit.cpp @@ -23,34 +23,43 @@ #define CONTRACT_ASSERT_AXIOM(cond) BOOST_CONTRACT_ASSERT(true || (cond)) template -bool random_binary_search(RandomIter first, RandomIter last, T const& value) { +RandomIter random_binary_search(RandomIter first, RandomIter last, + T const& value) { + RandomIter result; boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(first <= last); // Expensive O(n) assertion so marked "audit". CONTRACT_ASSERT_AUDIT(std::is_sorted(first, last)); }) + .postcondition([&] { + if(result != last) BOOST_CONTRACT_ASSERT(*result == value); + }) ; /* ... */ //] - while(first < last) { - RandomIter middle = first + ((last - first) >> 1); - BOOST_CONTRACT_CHECK(*first <= *middle || value < *middle || + RandomIter being = first, end = last; + while(begin < end) { + RandomIter middle = begin + ((end - begin) >> 1); + BOOST_CONTRACT_CHECK(*begin <= *middle || value < *middle || *middle < value); - if(value < *middle) last = middle; - else if(value > *middle) first = middle + 1; - else return true; + if(value < *middle) end = middle; + else if(value > *middle) begin = middle + 1; + else return result = middle; } - return false; + return result = last; } int main() { - std::vector i(3); - i[0] = 'a'; i[1] = 'b'; i[2] = 'c'; - assert(random_binary_search(i.begin(), i.end(), 'b')); + std::vector v(3); + v[0] = 'a'; v[1] = 'b'; v[2] = 'c'; + std::vector::iterator i = random_binary_search(v.begin(), v.end(), + 'b'); + assert(i != v.end()); + assert(*i == 'b'); return 0; } diff --git a/example/features/introduction.cpp b/example/features/introduction.cpp index 898f765..a4a944f 100644 --- a/example/features/introduction.cpp +++ b/example/features/introduction.cpp @@ -11,7 +11,7 @@ #include void inc(int& x) { - boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); // Old values. + boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); // Old value. boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(x < std::numeric_limits::max()); // Line 17. diff --git a/example/features/named_override.cpp b/example/features/named_override.cpp index 4c15c65..5d1500e 100644 --- a/example/features/named_override.cpp +++ b/example/features/named_override.cpp @@ -52,12 +52,12 @@ public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES - // BOOST_CONTRACT_OVERRIDE(_1) would generate reserved symbol `override__1`. + // BOOST_CONTRACT_OVERRIDE(_1) would generate reserved name `override__1`. BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1) // Generate `override1`. virtual void _1(T const& value, boost::contract::virtual_* v = 0) /* override */ { - // Use `override1` type generated by NAMED_OVERRIDE macro above. + // Use `override1` generated by BOOST_CONTRACT_NAMED_OVERRIDE above. boost::contract::check c = boost::contract::public_function( v, static_cast old_y; // But old value copied later... + boost::contract::old_ptr old_y; // Null, old value copied later... boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(index < s.size()); }) .old([&] { // ...after preconditions (and invariants) checked. - old_y = BOOST_CONTRACT_OLDOF(s[index]); // Checked `index` in range. + old_y = BOOST_CONTRACT_OLDOF(s[index]); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(s[index] == x); diff --git a/example/features/old_if_copyable.cpp b/example/features/old_if_copyable.cpp index a5553a5..2c5d65c 100644 --- a/example/features/old_if_copyable.cpp +++ b/example/features/old_if_copyable.cpp @@ -10,7 +10,7 @@ #include //[old_if_copyable_offset -template +template // T might or might not be copyable. void offset(T& x, int count) { // No compiler error if T has no copy constructor... boost::contract::old_ptr_if_copyable old_x = BOOST_CONTRACT_OLDOF(x); @@ -29,7 +29,7 @@ void offset(T& x, int count) { // Copyable type but... class w { public: - w(w const&) { /* Some very expensive copy here operation... */ } + w(w const&) { /* Some very expensive copy here operation here... */ } /* ... */ //] @@ -87,11 +87,11 @@ namespace boost { namespace contract { //] //[old_if_copyable_n_decl -// Non-copyable type so... -class n { +class n { // Do not want to use boost::noncopyable but... int num_; - n(n const&); // Unimplemented private copy constructor (not copyable). +private: + n(n const&); // ...unimplemented private copy constructor (so non-copyable). /* ... */ //] @@ -104,7 +104,7 @@ public: }; //[old_if_copyable_n_spec -// ...specialize `boost::is_copy_constructible` (no need for this on C++11). +// Specialize `boost::is_copy_constructible` (no need for this on C++11). namespace boost { namespace contract { template<> struct is_old_value_copyable : boost::false_type {}; diff --git a/example/features/private_protected.cpp b/example/features/private_protected.cpp index 60bd02d..02166a3 100644 --- a/example/features/private_protected.cpp +++ b/example/features/private_protected.cpp @@ -10,9 +10,8 @@ //[private_protected class counter { - // Private and protected functions use `function()` (like non-members). -protected: - virtual void set(int n, boost::contract::virtual_* = 0) { +protected: // Protected functions use `function()` (like non-members). + void set(int n) { boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(n <= 0); @@ -25,7 +24,7 @@ protected: n_ = n; } -private: +private: // Private functions use `function()` (like non-members). void dec() { boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); boost::contract::check c = boost::contract::function() @@ -47,7 +46,7 @@ private: //] public: - virtual int get(boost::contract::virtual_* v = 0) const { + int get() const { int result; boost::contract::check c = boost::contract::public_function( v, result, this) diff --git a/example/features/private_protected_virtual.cpp b/example/features/private_protected_virtual.cpp index dfc8775..1dfa608 100644 --- a/example/features/private_protected_virtual.cpp +++ b/example/features/private_protected_virtual.cpp @@ -11,10 +11,10 @@ //[private_protected_virtual_counter class counter { // Virtual private and protected functions still declare extra - // `virtual_* = 0` parameter (otherwise they cannot be overridden). + // `virtual_* = 0` parameter (otherwise they cannot be overridden), but... protected: virtual void set(int n, boost::contract::virtual_* = 0) { - boost::contract::check c = boost::contract::function() + boost::contract::check c = boost::contract::function() // ...no `v`. .precondition([&] { BOOST_CONTRACT_ASSERT(n <= 0); }) @@ -28,8 +28,8 @@ protected: private: virtual void dec(boost::contract::virtual_* = 0) { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); - boost::contract::check c = boost::contract::function() + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); // ...no `v`. + boost::contract::check c = boost::contract::function() // ...no `v`. .precondition([&] { BOOST_CONTRACT_ASSERT( get() + 1 >= std::numeric_limits::min()); diff --git a/example/features/public.cpp b/example/features/public.cpp index 7a4b42d..b488b09 100644 --- a/example/features/public.cpp +++ b/example/features/public.cpp @@ -75,7 +75,7 @@ public: //[public_virtual_function public: // Contract for a public virtual function (but no override). - virtual int push_back(int id, boost::contract::virtual_* v = 0) { + virtual int push_back(int id, boost::contract::virtual_* v = 0) { // Extra `v`. int result; boost::contract::old_ptr old_find = BOOST_CONTRACT_OLDOF(v, find(id)); // Pass `v`. @@ -84,8 +84,7 @@ public: boost::contract::check c = boost::contract::public_function( v, result, this) // Pass `v` and `result`. .precondition([&] { - // Specified identifier must not already be in container. - BOOST_CONTRACT_ASSERT(!find(id)); + BOOST_CONTRACT_ASSERT(!find(id)); // ID cannot be already present. }) .postcondition([&] (int const result) { if(!*old_find) { @@ -136,8 +135,7 @@ public: override_push_back // Pass override plus below function pointer... >(v, result, &identifiers::push_back, this, id) // ...and arguments. .precondition([&] { // Check in OR with bases. - // Do nothing if specified identifier already in container. - BOOST_CONTRACT_ASSERT(find(id)); + BOOST_CONTRACT_ASSERT(find(id)); // ID can be already present. }) .postcondition([&] (int const result) { // Check in AND with bases. if(*old_find) BOOST_CONTRACT_ASSERT(size() == *old_size); diff --git a/example/features/pure_virtual_public.cpp b/example/features/pure_virtual_public.cpp index 78f6dd8..49e36c9 100644 --- a/example/features/pure_virtual_public.cpp +++ b/example/features/pure_virtual_public.cpp @@ -8,40 +8,40 @@ #include #include -//[pure_virtual_public_base +//[pure_virtual_public_base_begin template class range { public: - // Pure virtual function declaration (contract not here, below instead). + // Pure virtual function declaration (contract in definition below). virtual Iterator begin(boost::contract::virtual_* v = 0) = 0; - - /* ... */ //] // Could program class invariants and contracts for the following too. virtual Iterator end() = 0; virtual bool empty() const = 0; -}; -//[pure_virtual_public_impl +//[pure_virtual_public_base_end + /* ... */ +}; +//] + +//[pure_virtual_public_base_impl // Pure virtual function default implementation (out-of-line in C++). template Iterator range::begin(boost::contract::virtual_* v) { - Iterator result; - // Pass `result` right after `v`... + Iterator result; // As usual, virtual pass `result` right after `v`... boost::contract::check c = boost::contract::public_function(v, result, this) - // ...plus postconditions take `result` as parameter (not capture). .postcondition([&] (Iterator const& result) { if(empty()) BOOST_CONTRACT_ASSERT(result == end()); }) ; - assert(false); // Pure function body never executed by this library. + // Pure function body (never executed by this library). + assert(false); return result; } //] -//[pure_virtual_public_derived template class vector #define BASES public range::iterator> @@ -65,9 +65,7 @@ public: return result = vect_.begin(); } - - /* ... */ -//] + BOOST_CONTRACT_OVERRIDE(begin) // Could program class invariants and contracts for the following too. iterator end() { return vect_.end(); } @@ -75,8 +73,6 @@ public: T const& front() const { return vect_.front(); } void push_back(T const& value) { vect_.push_back(value); } - BOOST_CONTRACT_OVERRIDE(begin) - private: std::vector vect_; }; diff --git a/example/n1962/vector_n1962.hpp b/example/n1962/vector_n1962.hpp index 9908da5..4b24bd0 100644 --- a/example/n1962/vector_n1962.hpp +++ b/example/n1962/vector_n1962.hpp @@ -270,8 +270,8 @@ public: postcondition { size() == count; if constexpr(boost::has_equal_to::value) { - if(count > oldof size()) { - boost::algorithm::all_of_equal(begin() + oldof size(), + if(count > oldof(size())) { + boost::algorithm::all_of_equal(begin() + oldof(size()), end(), value); } } @@ -401,8 +401,8 @@ public: size() < max_size(); } postcondition { - size() == oldof size() + 1; - capacity() >= oldof capacity() + size() == oldof(size()) + 1; + capacity() >= oldof(capacity()) if constexpr(boost::has_equal_to::value) { back() == value; } @@ -425,7 +425,7 @@ public: !empty(); } postcondition { - size() == oldof size() - 1; + size() == oldof(size()) - 1; } { vect_.pop_back(); @@ -471,12 +471,12 @@ public: size() < max_size(); } postcondition(result) { - size() == oldof size() + 1; - capacity() >= oldof capacity(); + size() == oldof(size()) + 1; + capacity() >= oldof(capacity()); if constexpr(boost::has_equal_to::value) { *result == value; } - // if(capacity() > oldof capacity()) + // if(capacity() > oldof(capacity())) // [begin(), end()) is invalid // else // [where, end()) is invalid @@ -500,12 +500,12 @@ public: size() + count < max_size(); } postcondition { - size() == oldof size() + count; - capacity() >= oldof capacity(); + size() == oldof(size()) + count; + capacity() >= oldof(capacity()); if constexpr(boost::has_equal_to::value) { - if(capacity() == oldof capacity()) { - boost::algorithm::all_of_equal(boost::prior(oldof where), - boost::prior(oldof where) + count, value); + if(capacity() == oldof(capacity())) { + boost::algorithm::all_of_equal(boost::prior(oldof(where)), + boost::prior(oldof(where)) + count, value); } // [where, end()) is invalid } @@ -535,12 +535,12 @@ public: // [first, last) is not contained in [begin(), end()) } postcondition { - size() == oldof size() + std::distance(first, last); - capacity() >= oldof capacity(); + size() == oldof(size()) + std::distance(first, last); + capacity() >= oldof(capacity()); if constexpr(boost::has_equal_to::value) { - if(capacity() == oldof capacity()) { - boost::algorithm::all_of_equal(boost::prior(oldof where), - boost::prior(oldof where) + count, value); + if(capacity() == oldof(capacity())) { + boost::algorithm::all_of_equal(boost::prior(oldof(where)), + boost::prior(oldof(where)) + count, value); } // [where, end()) is invalid } @@ -589,7 +589,7 @@ public: size() >= std::distance(first, lasst); } postcondition(result) { - size() == oldof size() - std::distance(first, last); + size() == oldof(size()) - std::distance(first, last); if(empty()) result == end(); // [first, last) is invalid } @@ -619,8 +619,8 @@ public: } postcondition { if constexpr(boost::has_equal_to::value) { - *this == oldof other; - other == oldof *this; + *this == oldof(other); + other == oldof(*this); } } { diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp index 1f03ca1..71299b2 100644 --- a/include/boost/contract/call_if.hpp +++ b/include/boost/contract/call_if.hpp @@ -64,7 +64,7 @@ Usually this class template is instantiated only via the return value of @c internal_type in this documentation). */ template struct call_if_statement : call_if_statement::type @@ -343,7 +343,7 @@ Usually this class template is instantiated only via the return value of */ template // Copyable (no data). struct call_if_statement - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CALL_IF_RESULT_OF_(Else) #else typename result_of::type @@ -561,7 +561,7 @@ trivially return @p else_ (@c true by default) at run-time. @return Boolean value returned by @c f() if the static predicate @c Pred is @c true. Otherwise, trivially return @p else_. */ -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN template bool condition_if_c(Then f, bool else_ = true); #else diff --git a/include/boost/contract/check.hpp b/include/boost/contract/check.hpp index bebe595..ef30c1a 100644 --- a/include/boost/contract/check.hpp +++ b/include/boost/contract/check.hpp @@ -126,7 +126,7 @@ public: template /* implicit */ check(specify_precondition_old_postcondition_except< VirtualResult> const& contract) - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CHECK_CTOR_DEF_( specify_precondition_old_postcondition_except) #else @@ -156,7 +156,7 @@ public: template /* implicit */ check(specify_old_postcondition_except const& contract) - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CHECK_CTOR_DEF_( specify_old_postcondition_except) #else @@ -186,7 +186,7 @@ public: template /* implicit */ check(specify_postcondition_except const& contract) - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CHECK_CTOR_DEF_( specify_postcondition_except) #else @@ -215,7 +215,7 @@ public: Otherwise, this is always @c void. */ /* implicit */ check(specify_except const& contract) - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_except) #else ; @@ -243,7 +243,7 @@ public: Otherwise, this is always @c void. */ /* implicit */ check(specify_nothing const& contract) - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_nothing) #else ; diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index 602c4b0..a93bf71 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -16,7 +16,7 @@ Configure this library compile-time and run-time behaviours. // headers after that depending on the contract 0/1 macros below ensuring no // compilation overhead. -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Define this macro to compile this library as a static (instead of shared) library (undefined by default). @@ -39,7 +39,7 @@ Configure this library compile-time and run-time behaviours. #error "STATIC_LINK defined with HEADER_ONLY and/or ALL_DYN_LINK" #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Define this macro when compiling user code to avoid compiling this library (undefined by default). @@ -64,7 +64,7 @@ Configure this library compile-time and run-time behaviours. #error "HEADER_ONLY defined with STATIC_LINK and/or ALL_DYN_LINK" #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Define this macro to not lock internal library data for thread safety (undefined by default). @@ -155,7 +155,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_STATIC_INVARIANT_FUNC static_invariant #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Disable some compile-time errors generated by this library (undefined by default). @@ -178,7 +178,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_PERMISSIVE #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Code block to execute if contracts are not assigned to a @RefClass{boost::contract::check} variable (undefined by default). @@ -202,7 +202,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_ON_MISSING_CHECK_DECL #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Define this macro to not disable other assertions while checking preconditions (undefined by default). @@ -222,7 +222,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Define this macro to not disable any assertions while checking any other assertion (undefined by default). @@ -239,7 +239,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** If defined, this library does not perform implementation checks (undefined by default). @@ -260,7 +260,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_NO_CHECKS #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** If defined, this library does not check preconditions (undefined by default). @@ -283,7 +283,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_NO_PRECONDITIONS #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** If defined, this library does not check postconditions (undefined by default). @@ -306,7 +306,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_NO_POSTCONDITIONS #endif -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** If defined, this library does not check exception guarantees (undefined by default). @@ -329,7 +329,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_NO_EXCEPTS #endif -#if defined(DOXYGEN) || \ +#if defined(BOOST_CONTRACT_DETAIL_DOXYGEN) || \ ( \ !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) && \ defined(BOOST_CONTRACT_NO_INVARIANTS) \ @@ -359,7 +359,7 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_NO_ENTRY_INVARIANTS #endif -#if defined(DOXYGEN) || \ +#if defined(BOOST_CONTRACT_DETAIL_DOXYGEN) || \ ( \ !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) && \ defined(BOOST_CONTRACT_NO_INVARIANTS) \ @@ -644,7 +644,7 @@ Configure this library compile-time and run-time behaviours. #ifdef BOOST_CONTRACT_DYN_LINK #error "define STATIC_LINK or HEADER_ONLY instead" -#elif defined(DOXYGEN) || \ +#elif defined(BOOST_CONTRACT_DETAIL_DOXYGEN) || \ defined(BOOST_ALL_DYN_LINK) || \ ( \ !defined(BOOST_CONTRACT_STATIC_LINK) && \ diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index 669e922..66e753c 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -24,7 +24,7 @@ Handle contract assertion failures. // #defined, because user code might explicitly call precondition_failure() // (for whatever reason...). Otherwise, the public API of this lib will change. -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN // Needed for `std::` prefix to show (but removed via `EXCLUDE_SYMBOLS=std`). namespace std { class exception {}; diff --git a/include/boost/contract/core/specify.hpp b/include/boost/contract/core/specify.hpp index cc10033..50371a4 100644 --- a/include/boost/contract/core/specify.hpp +++ b/include/boost/contract/core/specify.hpp @@ -474,7 +474,7 @@ old values at body, check postconditions, and check exception guarantees. */ template< typename VirtualResult /* = void (already in fwd decl from decl.hpp) */ - #ifdef DOXYGEN + #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN = void #endif > diff --git a/include/boost/contract/old.hpp b/include/boost/contract/old.hpp index 37233be..3acd910 100644 --- a/include/boost/contract/old.hpp +++ b/include/boost/contract/old.hpp @@ -285,7 +285,7 @@ public: return 0; } - #ifndef DOXYGEN + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr, !!typed_copy_) #else @@ -390,7 +390,7 @@ public: return 0; } - #ifndef DOXYGEN + #ifndef DBOOST_CONTRACT_DETAIL_OXYGEN BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr_if_copyable, !!typed_copy_) #else diff --git a/include/boost/contract/public_function.hpp b/include/boost/contract/public_function.hpp index 1a65f22..bd33670 100644 --- a/include/boost/contract/public_function.hpp +++ b/include/boost/contract/public_function.hpp @@ -226,7 +226,7 @@ specify_precondition_old_postcondition_except<> public_function(Class* obj) { /** @endcond */ -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Program contracts for void virtual public functions that do not override. @@ -413,7 +413,7 @@ specify_precondition_old_postcondition_except<> public_function(Class* obj) { /** @endcond */ -#ifdef DOXYGEN +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN /** Program contracts for void public functions overrides (virtual or not).