diff --git a/README.md b/README.md index 10b21fa7..18fee598 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org ### Properties * C++11 (C++03 possible but not recommended without lambda functions and variadic macros, see documentation for more information). -* Shared Library / DLL with `BOOST_CONTRACT_DYN_LINK` (static library with `BOOST_CONTRACT_STATIC_LINK` and header-only with `BOOST_CONTRACT_HEADER_ONLY` possible but not recommended, see documentation for more information). +* Shared Library / DLL with `BOOST_CONTRACT_DYN_LINK` (static library with `BOOST_CONTRACT_STATIC_LINK` and header-only with `BOOST_CONTRACT_HEADER_ONLY` also possible but not recommended, see documentation for more information). ### Build Status diff --git a/doc/advanced.qbk b/doc/advanced.qbk index e05ea676..0d094653 100644 --- a/doc/advanced.qbk +++ b/doc/advanced.qbk @@ -6,7 +6,7 @@ [section Advanced] -This section is a guide to advanced usages of this library. +This section is a guide to advanced usage of this library. [section Pure Virtual Public Functions] @@ -28,9 +28,6 @@ Therefore, programmers can safely `assert(false)` at the beginning of the body i 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): -[footnote -This consequence of the __substitution_principle__ ["that if any function in an inheritance hierarchy has no preconditions, then preconditions on functions overriding it have no useful effect] is also explicitly mentioned in the contract documentation of the D Programming Language (see __Bright04__). -] class u { // Some base class. public: @@ -47,7 +44,10 @@ This consequence of the __substitution_principle__ ["that if any function in an }; This correctly reflects the fact that the overridden function in the base class can be called from any context (because it has no precondition) and so must all its overriding functions in all derived classes in accordance to the __substitution_principle__. -In other words, the code above has the effect as declaring the virtual public function in the base class with a single precondition `BOOST_CONTRACT_ASSERT(true)` that will always trivially pass: +[footnote +This consequence of the __substitution_principle__ ["that if any function in an inheritance hierarchy has no preconditions, then preconditions on functions overriding it have no useful effect] is also explicitly mentioned in the contract documentation of the D Programming Language (see __Bright04__). +] +In other words, the code above has the same effect as declaring the virtual public function in the base class with a single precondition `BOOST_CONTRACT_ASSERT(true)` that will always trivially pass: class u { // Some base class. public: @@ -73,7 +73,7 @@ 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. +That said, the need to declare such a precondition `BOOST_CONTRACT_ASSERT(false)` that will always fail might also 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] @@ -83,7 +83,7 @@ In general, the base class interface should still contain all functions (eventua It is possible to use `boost::optional` to handle return values when programmers cannot construct the result variable at its point of declaration before the contract (e.g., because an appropriate constructor for the return type is not available at that point, or just because it would be too expensive to execute an extra initialization of the return value at run-time). [footnote *Rationale:* -This library uses `boost::optional` instead of `std::optional` because `std::optional` is not available before C++17. +This library uses `boost::optional` instead of `std::optional` to support a larger number of compilers and their versions (because `std::optional` was not available before C++17). ] For example (see [@../../example/features/optional_result.cpp =optional_result.cpp=]): @@ -92,15 +92,15 @@ For example (see [@../../example/features/optional_result.cpp =optional_result.c 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 assign to `result` so `vect[Index]` cannot be used to initialize `result` when it is declared before the contract declaration. -Therefore, `boost::optional` is used to defer `result` proper initialization until the execution of the function body, after the contract declaration, where `Index` has been validated by the precondition and `vect[Index]` can be safely evaluated to initialize `result`. +Therefore, `boost::optional` is used to defer `result` real initialization until the execution of the function body, after the contract declaration, where `Index` has been validated by the precondition and `vect[Index]` can be safely evaluated to initialize `result`. As seen in __Return_Values__, it is the responsibility of the programmers to ensure that `result` is always set to the return value (when the function exits without trowing an exception). This also ensures that `result` is always set before the postconditions are checked so programmers can always dereference `result` in postconditions to access the return value (using `operator*` and `operator->` as usual with `boost::optional`, and without having to explicitly check if `result` is an empty `boost::optional` object or not). -This can be done ensuring that /all/ return statements in the function are of the form: +This can be done ensuring that /all/ `return` statements in the function are of the form: - boost::optional result; + boost::optional<``[^['return-type]]``> result; ... - return *(result = return_expr); // Assign `result` at each return. + return *(result = ``[^['return-expression]]``); // Assign `result` at each return. [heading Optional Results in Virtual Public Functions] @@ -124,8 +124,8 @@ In addition, programmers are encouraged to declare the postcondition functor to [section Private and Protected Functions] 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] (because, like for non-member functions, this does not check class invariants and does not subcontract). +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 use (from within the class, base classes, friend classes or functions, etc.). +When programmers decide to specify contracts for private and protected functions, they can use [funcref boost::contract::function] (because, like for non-member functions, this does not check class invariants and does not subcontract). For example (see [@../../example/features/private_protected.cpp =private_protected.cpp=]): [import ../example/features/private_protected.cpp] @@ -146,7 +146,7 @@ For example (see [@../../example/features/private_protected_virtual.cpp =private [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 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). +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] @@ -162,14 +162,14 @@ For example (see [@../../example/features/private_protected_virtual_multi.cpp =p [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 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 correctly be done on GCC or Clang instead. +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 (at least up to Visual Studio 2015), but that can correctly be done on GCC or Clang instead. ] [endsect] [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. +In general, friend functions are not member functions so [funcref boost::contract::function] is used to program their contracts and all considerations made in __Non_Member_Functions__ apply. For example (see [@../../example/features/friend.cpp =friend.cpp=]): [import ../example/features/friend.cpp] @@ -184,7 +184,7 @@ For example (see [@../../example/features/friend_invariant.cpp =friend_invariant Contract programming proposals for C++ like __N1962__ do not provide a mechanism for friend functions to check class invariants of objects passed as parameters. In other words, these proposals do not enable contracts to recognize that in C++ some friend functions logically act as if they were part of the public interface of the objects they take as parameters. This is 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). +However, this library provides 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] @@ -206,7 +206,7 @@ For example: boost::contract::check inv1 = boost::contract::public_function(&object1); boost::contract::check inv2 = boost::contract::public_function(object2); // Check postconditions and exception guarantees. - boost::contract::check post_except = boost::contract::function() + boost::contract::check postex = boost::contract::function() .postcondition(...) .except(...) ; @@ -215,7 +215,7 @@ For example: } Changing the order of the [classref boost::contract::check] declarations above, programmers can chose the order for checking class invariants among the different objects passed to the friend function and also whether to check these invariants before or after preconditions, postconditions, and exception guarantees of the friend function (see __Non_Member_Functions__ and __Public_Functions__ for information on how the RAII objects returned by [funcref boost::contract::function] and [funcref boost::contract::public_function] check contract conditions). -The example above is programmed to check `class1` invariants before `class2` invariants (but the order could have been inverted if programmers so chose). +The example above is programmed to check `class1` invariants before `class2` invariants (but that order could have been inverted if programmers so chose). [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). @@ -269,11 +269,11 @@ 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 and classes declared `constexpr`. +The library does not support contracts for functions and classes declared `constexpr`. [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 `constexpr` functions and classes because C++ does not currently allow `constexpr` functions to do the following: +However, the current implementation of this library cannot support contracts for `constexpr` functions and classes because C++ does not currently allow `constexpr` functions to do the following: Declare local variables of (literal) types with non-trivial `constexpr` destructors (this RAII technique is used by this library to check invariants, postconditions, and exceptions guarantees at exit); Call other `constexpr` functions using try-catch statements (used by this library to report contract assertion failures and catch any other exception that might be thrown when evaluating the asserted conditions); Use lambda functions (used by this library for convenience to program functors that that check preconditions, postconditions, and exception guarantees). @@ -284,34 +284,34 @@ Also note that even if supported, contracts for `constexpr` functions probably w [section Implementation Checks] -This library provides a mechanism to check assertions within implementation code a part from preconditions, postconditions, exceptions guarantees, and class invariants. -Implementation checks are programmed using a nullary functor that is directly assigned to a [classref boost::contract::check] object declaration right at the place within the code where the checks need to be performed (without calling [funcref boost::contract::function], [funcref boost::contract::public_function], etc. in this case). +This library provides also a mechanism to check assertions within implementation code (differently from preconditions, postconditions, exceptions guarantees, and class invariants that are instead checked before or after code that implements a function body). +These /implementation checks/ are programmed using a nullary functor that is directly assigned to a [classref boost::contract::check] object declaration right at the place within the code where the checks need to be performed (without calling [funcref boost::contract::function], [funcref boost::contract::public_function], etc. in this case). For example (see [@ ../../example/features/check.cpp =check.cpp=]): [import ../example/features/check.cpp] [check] -The implementation check functor should capture all the variables that it needs to assert the implementation checks. +The implementation check functor should capture all the variables that it needs for its assertions. These variables can be captured by value when the overhead of copying such variables is acceptable. -In any case, implementation checks should not modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__). +In any case, programmers should not write implementation checks that modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__). Any code can be programmed in the implementation check functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex checks that might be buggy and also slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call the failure handler [funcref boost::contract::check_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if calling the implementation check functor throws any exception. +This library will automatically call the failure handler [funcref boost::contract::check_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false or, more in general, if calling the implementation check functor throws any exception. By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). -Similarly to the C-style `assert` macro that is disable when `NDEBUG` is defined, implementation checks are disabled when [macroref BOOST_CONTRACT_NO_CHECKS] is defined. +Similarly to the C-style `assert` macro that is disabled when `NDEBUG` is defined, implementation checks are disabled when [macroref BOOST_CONTRACT_NO_CHECKS] is defined (see __Disable_Contract_Checking__). That will skip all implementation checks at run-time but it will not eliminate some of the overhead of executing and compiling the related [classref boost::contract::check] declarations. -Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove run- and compile-time overhead of implementation checks when [macroref BOOST_CONTRACT_NO_CHECKS] is defined (this is not a variadic macro): +Alternatively, this library provides the [macroref BOOST_CONTRACT_CHECK] macro that allows to completely remove run- and compile-time overheads of implementation checks when [macroref BOOST_CONTRACT_NO_CHECKS] is defined (note that this is not a variadic macro): - BOOST_CONTRACT_CHECK(bool_cond) - // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_CHECK((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_CHECK(``[^['boolean-condition]]``) + // Or, if `boolean-condition` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_CHECK((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). For example (see [@ ../../example/features/check_macro.cpp =check_macro.cpp=]): @@ -320,27 +320,31 @@ For example (see [@ ../../example/features/check_macro.cpp =check_macro.cpp=]): The [macroref BOOST_CONTRACT_CHECK] macro is similar to the C-style assert macro as it accepts a boolean condition (instead of a nullary functor like [classref boost::contract::check] does). [footnote -Of course, nothing prevents programmers from calling functors to specify boolean conditions when if-guards and other statements are required to assert the implementation checks. -For example, programmers can use C++11 lambda functions to define and call such functors in place where the implementation checks are specified `BOOST_CONTRACT_CHECK([...] -> bool { ... } ())`. +Of course, nothing prevents programmers from calling functors within [macroref BOOST_CONTRACT_CHECK] to specify boolean conditions when if-guards and other statements are required to assert the implementation checks. +For example, programmers can use C++11 lambda functions to define and call such functors in place where the implementation checks are specified: +`` + BOOST_CONTRACT_CHECK([&] -> bool { + if(even_numbers) return gcd(x, y) == 2; + else return gcd(x, y) == 3; + } ()); +`` ] Using [macroref BOOST_CONTRACT_CHECK] is essentially equivalent to using the C-style `assert` macro a part from the following: * Implementation checks are disabled defining [macroref BOOST_CONTRACT_NO_CHECKS] (instead of `NDEBUG` for disabling `assert`). -* If the asserted boolean condition is either false or it throws an exception then this library will call [funcref boost::contract::check_failure] (instead `assert` calls `std::abort` if the asserted condition is false and unwinds the stack if evaluating the condition throws an exception). +* If the asserted boolean condition is either false or it throws an exception then this library will call [funcref boost::contract::check_failure] (instead `assert` calls `std::abort` if the asserted condition is false and it unwinds the stack if evaluating the condition throws an exception). * Implementation checks are automatically disabled when other contract conditions specified using this library are already being checked (to avoid infinite recursion, see [macroref BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION]). -(See __Disable_Contract_Checking__ and __Disable_Contract_Compilation__ for macros to completely remove run- and compile-time overhead also for preconditions, postconditions, exception guarantees, and class invariants.) - [endsect] -[section Old Value Copies at Body] +[section Old Values Copied 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] as soon as they are declared. -This is correctly happens before the function body is executed but also 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 practical cases, however technically old values should be copied before executing the function body but /after/ checking entry class invariants and preconditions (see __Assertions__). +That correctly happens before the function body is executed but also 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 practical cases however, technically speaking, old values should be copied before executing the function body but /after/ checking class invariants and preconditions at function entry (see __Assertions__). Specifically, there could be cases in which it makes sense to evaluate the expressions passed to [macroref BOOST_CONTRACT_OLDOF] only under the assumption that assertions programmed in class invariants and preconditions are true. -This library allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and then to later assign them to a copy of the expression passed to [macroref BOOST_CONTRACT_OLDOF] in a nullary functor [^['d]]`()` passed to `.old(`[^['d]]`)`. +This library allows to construct [classref boost::contract::old_ptr] variables using their default constructor (equivalent to a null pointer) and then to later assign them to a copy of the expression specified by [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. Old value assignments via `.old(...)` must appear after preconditions but before postconditions and exception guarantees wen these are all present (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). [footnote @@ -351,15 +355,15 @@ The enforced order for specifying preconditions, old value assignments, postcond Other contract programming frameworks allow to mix this order, that could have been implemented for this library as well but it would have complicated somewhat the library implementation while adding no real value (arguably creating confusion in user code by not enforcing a consistent order for specifying contract conditions). ] -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=]): +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 the valid range `index < s.size()`. +Therefore, `old_char` 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 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 __Constant_Correctness__). +The functor passed to `.old(...)` should capture all the variables that it needs to evaluate 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 copy the values the captured variables will have just before executing the function body, and not the values these variables had when the functor passed to `.old(...)` was first declared). +In any case, programmers should write the functor passed to `.old(...)` so that it modifies only old values and not the values of other captured variables, even when those are captured by reference (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_Failures__ to throw exceptions, exit the program with an error code, etc.). @@ -377,18 +381,18 @@ However, that will prevent this library from knowing the [enumref boost::contrac [section Named Overrides] -As seen in __Public_Function_Overrides__, the [macroref BOOST_CONTRACT_OVERRIDE] macro has to be used to declare a type `override_...` that is passed to [funcref boost::contract::public_function] for public function overrides. -The function names passed to [macroref BOOST_CONTRACT_OVERRIDE] (and [macroref BOOST_CONTRACT_OVERRIDES]) should never start with an underscore to avoid generating names containing double underscores `override__...` (which are reserved by the C++ standard). +As seen in __Public_Function_Overrides__, the [macroref BOOST_CONTRACT_OVERRIDE] macro has to be used to declare the type `override_...` that is passed as an explicit template parameter to [funcref boost::contract::public_function] for public function overrides. +The function names passed to [macroref BOOST_CONTRACT_OVERRIDE] (and [macroref BOOST_CONTRACT_OVERRIDES]) should never start with an underscore to avoid generating names containing double underscores `override__...` (because all symbols containing double underscores `...__...` are reserved symbols in the C++ standard). There is a separate macro [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that can be used to explicitly specify the name of the type being declared: [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 macro 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(func_name) // Generate `override_...`. - BOOST_CONTRACT_NAMED_OVERRIDE(type_name, func_name) // Generate `type_name`. + 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 declare a type named `override__1` (which is reserved in C++ because it contains double underscores `__`). thus `BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1)` is used to name the type `override1` instead (see [@../../example/features/named_override.cpp =named_override.cpp=]): +For example, the following public function override is named `_1` so `BOOST_CONTRACT_OVERRIDE(_1)` would declare a type named `override__1` (which is reserved symbol in C++ because it contains a double underscore `__`), thus `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] @@ -405,14 +409,14 @@ The authors found such a syntax less readable than repeating single [macroref BO [section Access Specifiers] -As we have seen so far, programmers are required to decorate their classes declaring the following extra members that are internally used by this library to check contracts: +As seen thus far, this library requires programmers to decorate their classes declaring the following extra members: * 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 `base_types` member `typedef` 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 so programmers should not actually use such a type even when it is declared `public`. +Note that 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 be able to access them. @@ -421,7 +425,7 @@ There is some variability among compiler implementations: The `base_types` member type needs to be declared `public` on MSVC, GCC, and 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` as shown in this section allows to always declare the extra members `private` on all compilers. +In any case, declaring these extra members all `public` or all `private` when the [classref boost::contract::access] class is also declared `friend` always works 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. @@ -430,7 +434,8 @@ For example (see [@../../example/features/access.cpp =access.cpp=]): [import ../example/features/access.cpp] [access] -This technique is not used in most examples of this documentation only for brevity, but programmers are encouraged to use it in real production code. +This technique is not used in most examples of this documentation only for brevity. +Programmers are encouraged to use [classref boost::contract::access] in real production code freely as they see fit. [warning Not declaring [classref boost::contract::access] 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. @@ -448,15 +453,15 @@ If a condition checked using [macroref BOOST_CONTRACT_ASSERT] is evaluated to be * 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 value copies at body: Exceptions thrown from old value copies at body within `.old(...)` call [funcref boost::contract::old_failure]. +* Old values copied at body: Exceptions thrown from old values copied 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 `BOOST_CONTRACT_CHECK(...)` call [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 a buggy program will be in a state for which no operation can be successfully performed, so the program should be stopped as soon as possible). +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 a buggy program will be in a state for which no operation can be successfully and safely performed, so the program should be stopped as soon as possible). 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 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, for specific applications, programmers could implement some fail-safe mechanism for which some mission-critical operations 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: @@ -464,10 +469,10 @@ However, programmers can override the default contract failure handlers to perfo * 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 value copies at body: [funcref boost::contract::set_old_failure]. +* Old values copied 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. +These `set_..._failure(`[^['f]]`)` function calls return a reference to the contract failure handler functor [^['f]] that they take as input parameter (so they can be concatenated). [footnote *Rationale:* The `set_..._failure` functions take a functor as parameter (to accept not just function pointers but also lambdas, binds, etc.) and they return this same functor as result so they can be concatenated (this interface is a bit different from `std::set_terminate`). @@ -481,32 +486,37 @@ For example (see [@../../example/features/throw_on_failure.cpp =throw_on_failure 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 (in fact destructors are implicitly declared `noexcept` since C++11). -This library passes a [enumref boost::contract::from] parameter to the contract failure handlers for preconditions, postconditions, class invariants, and old value copies at body (see [funcref boost::contract::precondition_failure], [funcref boost::contract::postcondition_failure], [funcref boost::contract::entry_invariant_failure], [funcref boost::contract::exit_invariant_failure], and [funcref boost::contract::old_failure] respectively). +This library passes a [enumref boost::contract::from] parameter to the contract failure handlers for preconditions, postconditions, class invariants, and old values copied at body (see [funcref boost::contract::precondition_failure], [funcref boost::contract::postcondition_failure], [funcref boost::contract::entry_invariant_failure], [funcref boost::contract::exit_invariant_failure], and [funcref boost::contract::old_failure] respectively). 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 production 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 not to throw exceptions from destructors, not even because of 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 otherwise these destructors will throw (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 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 (throwing an exception while there is already an active exception will force program termination or lead to undefined behaviour in C++). +* 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 otherwise these destructors will throw (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). [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). +Programmers need to decide how to handle contract failures from destructors when they write 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 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). ] +[heading Throw User-Defined Exceptions] + Contract assertions can be programmed to throw [classref boost::contract::assertion_failure] using `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, the following precondition functor throws [classref boost::contract:assertion_failure] (via [macroref BOOST_CONTRACT_ASSERT]) on its first assertion and the user-defined exception `too_large_error` on its second assertion (both exceptions will cause this library to call the customized [funcref boost::contract::precondition_failure] listed above which will in turn re-throw the exceptions up he stack, see [@../../example/features/throw_on_failure.cpp =throw_on_failure.cpp=]): +For example, the following precondition functor throws [classref boost::contract:assertion_failure] (via [macroref BOOST_CONTRACT_ASSERT]) on its first assertion and the user-defined exception `too_large_error` on its second assertion (both exceptions will cause this library to call the customized [funcref boost::contract::precondition_failure] listed above which will in turn re-throw the exceptions up the stack, 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 as well. +[heading Exception Specifiers (`noexcept` and `throw``)] + +Exception specifiers `noexcept` (since C++11) and `throw` (deprecated in C++11) of the enclosing function, constructor, or destructor 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 (specifically, 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] diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk index 661a581c..3d97fa21 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 more detailed introductions to contract programming). +This section gives an overview of contract programming (see __Meyer97__, __Mitchell02__, and __N1613__ for more extensive 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 in their code. -Then, this library aims to be the best and more complete contract programming library for C++ (without using preprocessors and other tools external to the C++ preprocessor and language itself). +Then, this library aims to be the best and more complete contract programming library for C++ (without using programs and tools external to the C++ language and its preprocessor). ] [section Assertions] @@ -23,33 +23,34 @@ Then, this library aims to be the best and more complete contract programming li Contract programming is characterized by the following assertion mechanisms: * /Preconditions/: These are logical conditions that programmers expect to be true when a function is called (e.g., to check constraints on function arguments). -Operations that logically have no preconditions (i.e., that are always well-defined for the entire domain of their inputs) are often referred to as having a /wide contract/. -This is in contrast to operations that have preconditions which are often referred to as having a /narrow contract/ (note that operations with truly narrow contracts are expected to also never throw exceptions). +Operations that logically have no preconditions (i.e., that are always well-defined for the entire domain of their inputs) are also referred to as having a /wide contract/. +This is in contrast to operations that have preconditions which are also referred to as having a /narrow contract/ (note that operations with truly narrow contracts are also expected to never throw exceptions because the implementation body of these operations is always expected to succeed after its preconditions are checked to be true). [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 just because the authors generally prefer to explicitly mention "this operation has no preconditions..." or "this operation has preconditions...". +This nomenclature is perfectly reasonable but it is not often used in this document just because the authors usually prefer to explicitly say "this operation has no preconditions..." or "this operation has preconditions..." (this is just a matter of taste). ] * /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 also /old values/ (which are the values that expressions had before the function body was executed). +Postconditions can access the function return value (for non-void functions) and also /old values/ (which are the values that expressions had before the function implementation was executed). * /Exception guarantees/: These are logical conditions that programmers except to be true when a function exits throwing an exception. Exception guarantees can access old values (but not the function return value). [footnote *Rationale:* -Contract assertions for exception guarantees were first introduced by this library (even if exception safety guarantees have long been part of C++ STL documentation). -Contract assertions for exception safety guarantees are not part of __N1962__ or other references listed in the __Bibliography__. +Contract assertions for exception guarantees were first introduced by this library, they are not part of __N1962__ or other references listed in the __Bibliography__ (even if exception safety guarantees have long been part of C++ STL documentation). ] * /Class invariants/: These are logical conditions that programmers expect to be true after a constructor exits without throwing an exception, before and after the execution of every non-static public function (even if they throw exceptions), before the destructor is executed (and also after the destructor is executed but only when the destructor throws an exception). Class invariants define valid states for all objects of a given class. -It is possible to specify a different set of class invariants for volatile public functions, namely volatile class invariants. +It is 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 public functions. -Static and volatile class invariants are not part of __N1962__ or other references listed in the __Bibliography__. +Static and volatile class invariants were first introduced by this library (simply to reflect the fact that C++ supports also static and volatile public functions), they are not part of __N1962__ or other references listed in the __Bibliography__. ] * /Subcontracting/: This indicates that preconditions cannot be strengthen, while postconditions and class invariants cannot be weaken when a public function in a derived class overrides public functions in one or more of its base classes (this is formally defined according to the __substitution_principle__). -Class invariants can also be used to specify /basic/ exception safety guarantees for an object (because they are checked at exit of public functions even when those throw exceptions), while contract assertions for exception guarantees can be used to specify /strong/ exception safety guarantees for given operations on the same object. +The actual function implementation code, that remains outside of these contract assertions, is often referred to as the /function body/ in contract programming. + +Class invariants can also be used to specify /basic/ exception safety guarantees for an object (because they are checked at exit of public functions even when those throw exceptions). +Contract assertions for exception guarantees can be used to specify /strong/ exception safety guarantees for a given operation 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). @@ -67,17 +68,18 @@ This is because when contract conditions are programmed together in a single ass [heading C-Style Assertions] -A limited form of contract programming is the use of the C-style `assert` macro. +A limited form of contract programming (typically some form of precondition and basic postcondition checking) can be achieved using the C-style `assert` macro. Using `assert` is common practice for many programmers but it suffers of the following limitations: * `assert` does not distinguish between preconditions and postconditions. -In well-tested production code, postconditions can usually be disabled trusting the correctness of the implementation while preconditions might still need to remain enabled because of possible changes in the calling code (e.g., postconditions of a given library could be disabled after testing while its preconditions can be kept enabled given the library cannot predict changes in the user code that will be calling the library). +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 keeping the library preconditions enabled given that future changes in the user code that calls the library cannot be anticipated). 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 correctly check postconditions (specifically to handle functions with multiple return statements, to not check postconditions when functions throw exceptions, and to implement old values). * `assert` requires to manually program extra code to check class invariants (extra member functions, try blocks, etc.). * `assert` does not support subcontracting. * `assert` calls are usually scattered within function implementations thus the asserted conditions are not immediately visible in their entirety by programmers (as they are instead when the assertions appear in the function declaration or at least at the very top of the function definition). -Contract programming does not suffers of these limitations. +Contract programming does not suffer of these limitations. [endsect] @@ -88,6 +90,7 @@ Contract programming does not suffers of these limitations. The main use of contract programming is to improve software quality. __Meyer97__ discusses how contract programming can be used as the basic tool to write ["correct] software. __Stroustrup94__ discusses the key importance of class invariants plus advantages and disadvantages of preconditions and postconditions. + The following is a short summary of benefits associated with contract programming inspired mainly by __N1613__: * Preconditions and postconditions: @@ -104,7 +107,7 @@ Class invariants can also be used as a criteria for good abstractions: If it is 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. * Easier debugging: -Contract programming can provide a powerful debugging facility because, if contracts are well written, bugs will cause contract assertions to fail exactly where the problem first occurs instead than at some later stage of the program execution in an apparently unrelated (and often hard to debug) manner. +Contract programming can provide a powerful debugging facility because, if contracts are well-written, bugs will cause contract assertions to fail exactly where the problem first occurs instead than at some later stage of the program execution in an apparently unrelated (and often hard to debug) manner. Note that a precondition failure points to a bug in the function caller, a postcondition failure points instead to a bug in the function implementation. [footnote Of course, if contracts are ill-written then contract programming is of little use. @@ -117,19 +120,18 @@ 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 (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 and guide, 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. +Contract programming can serve to reduce the gap between designers and programmers by providing a precise and unambiguous specification language in terms of contract assertions. Moreover, contracts can make code reviews easier by clarifying some of the semantics and usage of the code. -* Formalized inheritance: +* Formalize inheritance: Contract programming formalizes the virtual function overriding mechanism using subcontracting as justified by the __substitution_principle__. This keeps the base class programmers in control as overriding functions always have to fully satisfy the contracts of their base classes. * Replace defensive programming: Contract programming assertions can replace [@http://en.wikipedia.org/wiki/Defensive_programming defensive programming] checks localizing these checks within the contracts and making the code more readable. Of course, not all formal contract specifications can be asserted in C++. -For example, in C++ is it not possible to assert the validity of an iterator range in the general case because the only way to check if two iterators form a valid range is to keep incrementing the first iterator until we reach the second iterator. -However, in case the iterator range is invalid, such a code would render undefined behaviour or run forever instead of failing an assertion. +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 it reaches the second iterator, but if the iterator range is invalid then 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] @@ -141,7 +143,7 @@ The run-time performances are negatively impacted by contract programming mainly * Check the asserted conditions. * Copy old values when these are used in postconditions or exception guarantees. -* Call additional functors that check preconditions, postconditions, exception guarantees, class invariants, etc. (especially for subcontracting). +* Call additional functors that check preconditions, postconditions, exception guarantees, class invariants, etc. (these can add up to many extra calls especially when using 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. @@ -151,7 +153,7 @@ In addition to that, this library introduces a number of function calls internal ] 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 (see __Disable_Contract_Checking__): +Programmers will have to decide based on the performance trade-offs required by their specific 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. * Check preconditions, postconditions, class invariants, and maybe even exception guarantees during initial testing. @@ -179,7 +181,7 @@ A call to a non-member function with a contract executes the following steps (se Private and protected functions do not have to satisfy class invariants because these functions are part of the class implementation and not of the class public interface. Furthermore, the __substitution_principle__ does not apply to private and protected functions because these functions are not accessible to the user at the calling site where the __substitution_principle__ applies. -Therefore, calls to private and protected functions with contracts execute the same steps as the ones indicated above for non-member functions (checking only preconditions and postconditions, without checking class invariants and subcontracting). +Therefore, calls to private and protected functions with contracts execute the same steps as the ones indicated above for non-member functions (checking only preconditions and postconditions, without checking class invariants and without subcontracting). [endsect] @@ -187,11 +189,12 @@ Therefore, calls to private and protected functions with contracts execute the s [heading Overriding Public Functions] -Let's consider a public function in a derived class that overrides public virtual functions declared its public base classes (because of C++ multiple inheritance, the function could override from more than one of its base classes). +Let's consider a public function in a derived class that overrides public virtual functions declared by its public base classes (because of C++ multiple inheritance, the function could override from more than one of its base classes). We refer to the function in the derived class as the /overriding function/, and to the set of base classes containing all the /overridden functions/ as /overridden bases/. -When subcontracting, overridden functions are searched (at compile-time) deeply in the public branches of the inheritance tree (i.e., not just the derived class's direct public parents are inspected, but also all its public grandparents, etc.). -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). +When subcontracting, overridden functions are searched (at compile-time) deeply in all public branches of the inheritance tree (i.e., not just the derived class' direct public parents are inspected, but also all its public grandparents, etc.). +In case of multiple inheritance, this search also extends (at compile-time) widely to all public trees of the multiple inheritance forest (multiple public base classes are searched following their order of declaration in the derived class' inheritance list). +As usual with C++ multiple inheritance, 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. A call to the overriding public function with a contract executes the following steps (see [funcref boost::contract::public_function]): @@ -215,12 +218,12 @@ Furthermore, subcontracting checks contracts of public base classes before check 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. +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 are checked in __AND__ with preconditions, class invariants, postconditions, and exceptions guarantees of base classes respectively. ] [heading Non-Overriding Public Functions] -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]): +A call to a non-static public function with a contract (that does not override functions from any of its 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). @@ -240,7 +243,7 @@ However, none of the contracts of the base classes are checked because this func 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). +# Check function preconditions (but none of the preconditions from functions in base classes). # 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). @@ -265,8 +268,8 @@ A call to a constructor with a contract executes the following steps (see [class # 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 [^['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). + # Check constructor postconditions (but these cannot access the object old value [^['oldof]]`(*this)` because the object was not constructed before the execution of the constructor body). +# Else, check constructor exception guarantees (but these cannot access the object old value [^['oldof]]`(*this)` because the object was not constructed before the execution of the constructor body, plus they can only access class' static members because the object has not been successfully constructed given the constructor body threw an exception in this case). 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). @@ -282,7 +285,7 @@ A call to a destructor with a contract executes the following steps (see [funcre # 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 and the object old value [^['oldof]]`(*this)` 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 the object has been destroyed 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). @@ -290,7 +293,7 @@ However, in principle there could be uses for destructor postconditions so this ] # 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 (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 non-static __AND__ volatile class invariants (because the object was not successfully destructed so it still exists and should satisfy its invariants). # 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). @@ -307,9 +310,9 @@ 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 access objects, function arguments, function return values, old values, and all other program variables in `const` context (via `const&`, `const* const`, `const volatile`, etc.). -Whenever possible (e.g., class invariants and postcondition old values), this library automatically enforces this constant-correctness constraint at compile-time using `const`. +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 enforces the constant-correctness constraint at compile-time (but at the cost of significant boiler-plate code to be programmed manually so not recommended in general). +See __No_Lambda_Functions__ for ways of using this library that enforce the constant-correctness constraint at compile-time (but at the cost of significant boiler-plate code to be programmed manually so not recommended in general). [note In general, it is the responsibility of the programmers to code assertions that only check, and do not change, program variables. @@ -322,19 +325,19 @@ Note that this is true when using C-style `assert` as well. [section Specifications vs. Implementation] -Contracts are part of the program specifications and not of its implementation. +Contracts are part of the program specification and not of its implementation. Therefore, contracts should ideally be programmed within C++ declarations, and not within definitions. In general, this library cannot satisfy this requirement. However, even when contracts are programmed together with the body in the function definition, it is still fairly easy for users to identify and read just the contract portion of the function definition (because the contract code must always be programmed at the very top of the function definition). -See __Separate_Body_Implementation__ for ways of using this library to program contract specifications outside of the body implementation (but at the cost of writing one extra function for any given function, for applications where this requirement is truly important). +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 so not recommended in general). Furthermore, contracts are most useful when they assert conditions only using public members (in most cases, the need for using non-public members to check contracts, especially in preconditions, indicates an error in the class design). For example, the caller of a public function cannot in general make sure that the function preconditions are satisfied if the precondition assertions use private members that are not callable by the caller (therefore, a failure in the preconditions will not necessarily indicate a bug in the caller given that the caller was made unable to fully check the preconditions in the first place). -However, given that C++ provides programmers ways around access level restrictions (`friend`, function pointers, etc.), this library leaves it up to the programmers to make sure that only public members are used in contract assertions (especially in preconditions). (__N1962__ follows the same approach not restricting contracts to only use public members, Eiffel instead generates a compile-time error if preconditions are asserted using non-public members.) +However, given that C++ provides programmers ways around access level restrictions (`friend`, function pointers, etc.), this library leaves it up to programmers to make sure that only public members are used in contract assertions (especially in preconditions). (__N1962__ follows the same approach not restricting contracts to only use public members, Eiffel instead generates a compile-time error if preconditions are asserted using non-public members.) [footnote *Rationale:* -If C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] had not been fixed, this library could have been implemented 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++). +Out of curiosity, if C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] had not been fixed, this library could have been implemented to generate a compile-time error when precondition assertions use non-public members more similarly to Eiffel's implementation (but still, not necessary the best approach for C++). ] [endsect] @@ -342,6 +345,10 @@ If C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect [section On Contract Failures] If preconditions, postconditions, exception guarantees, or class invariants are either checked to be false or their evaluation throws an exception at run-time then this library will call specific /failure handler functions/. +[footnote +*Rationale:* +If the evaluation of a contract assertion throws an exception, the assertion cannot be checked to be true so the only safe thing to assume is that the assertion failed (indeed the contract assertion checking failed) and call the contract failure handler in this case also. +] By default, these failure handler functions print a message to the standard error `std::cerr` (with detailed information about the failure) and then terminate the program calling `std::terminate`. However, using [funcref boost::contract::set_precondition_failure], [funcref boost::contract::set_postcondition_failure], [funcref boost::contract::set_except_failure], [funcref boost::contract::set_invariant_failure], etc. programmers can define their own failure handler functions that can take any user-specified action (throw an exception, exit the program with an error code, etc., see __Throw_on_Failures__). @@ -353,7 +360,7 @@ This customizable failure handling mechanism is similar to the one used by C++ ` [note In C++ there are a number of issues with programming contract failure handlers that throw exceptions instead of terminating the program. Specifically, destructors check class invariants so they will throw if programmers change class invariant failure handlers to throw instead of terminating the program, but in general destructors should not throw in C++ (to comply with STL exception safety, C++11 implicit `noexcept` declarations for destructors, etc.). -Furthermore, programming a failure handler that throws for exception guarantees will throw an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception guarantees to be checked in the first place), and this will force C++ to terminate the program anyway. +Furthermore, programming a failure handler that throws on exception guarantee failures results in throwing an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception guarantees to be checked in the first place), and this will force C++ to terminate the program anyway. ] Therefore, it is recommended to terminate the program at least for contract failures from destructors and exception guarantees (if not in all other cases of contract failures as it is done by default by this library). @@ -364,7 +371,9 @@ The contract failure handler functions programmed using this library have inform [section Feature Summary] The contract programming features supported by this library are largely based on __N1962__ and on the Eiffel programming language. -The following table compares contract programming features among this library, __N1962__ (unfortunately the C++ standard committee rejected this proposal commenting on a lack of interest in adding contract programming to C++ at that time, even if __N1962__ itself is sound), a more recent proposal __P0380__ (which has gain some traction within the C++ standard committee but unfortunately only supports preconditions and postconditions, while does not support class invariants, old values, and subcontracting), the Eiffel and D programming languages: + +The following table compares contract programming features among this library, __N1962__ (unfortunately the C++ standard committee rejected this proposal commenting on a lack of interest in adding contract programming to C++ at that time, even if __N1962__ itself is sound), a more recent proposal __P0380__ (which was accepted in the C++20 standard but unfortunately only supports preconditions and postconditions, while does not support class invariants, old values, and subcontracting), the Eiffel and D programming languages. +Some of the items listed in this summary table will become clear in detail after reading the remaining sections of this documentation. [table [ @@ -401,8 +410,8 @@ The last three specifiers appear in user code so their names can be referred to ][ [['Old values in postconditions]] [ -Yes, [macroref BOOST_CONTRACT_OLDOF] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old(...)` is used as shown in __Old_Value_Copies_at_Body__). -For templates, [classref boost::contract::old_ptr_if_copyable] skips old value copies for non-copyable types and [funcref boost::contract::condition_if] skips old value copies selectively based on old expression type requirements. +Yes, [macroref BOOST_CONTRACT_OLDOF] macro and [classref boost::contract::old_ptr] (but copied before preconditions unless `.old(...)` is used as shown in __Old_Values_Copied_at_Body__). +For templates, [classref boost::contract::old_ptr_if_copyable] skips old value copies for non-copyable types and [funcref boost::contract::condition_if] skips old value copies selectively based on old expression type requirements (on compilers that do not support `if constexpr`). ] [ Yes, `oldof` keyword (copied right after preconditions). @@ -438,7 +447,7 @@ However, invariants cannot call public functions (to avoid infinite recursion be ][ [['Subcontracting]] [ -Yes, also supports subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used for declaring base classes, overrides and virtual public functions respectively). +Yes, also supports subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used to declare base classes, overrides and virtual public functions respectively). ] [ Yes, also supports subcontracting for multiple inheritance, but preconditions cannot be subcontracted. @@ -446,9 +455,8 @@ Yes, also supports subcontracting for multiple inheritance, but preconditions ca *Rationale:* The authors of __N1962__ decided to forbid derived classes from subcontracting preconditions because they found that such a feature was rarely, if ever, used (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). Still, it should be noted that even in __N1962__ if a derived class overrides two functions with preconditions coming from two different base classes via multiple inheritance, the overriding function contract will check preconditions from its two base class functions in __OR__ (so even in __N1962__ preconditions can indirectly subcontract when multiple inheritance is used). -The authors of this library found that confusing about __N1962__. Furthermore, subcontracting preconditions is soundly defined by the __substitution_principle__ so this library allows to subcontract preconditions as Eiffel does (users can always avoid using this feature if they have no need for it). -(This is essentially the only feature on which this library deliberately differ from __N1962__.) +(This is essentially the only feature on which this library deliberately differs from __N1962__.) ] ] [No.] @@ -465,14 +473,14 @@ 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 (use of only public functions to program preconditions is recommended but not prescribed).] - [No, assertions only (in addition only public members can be used in preconditions).] + [No, assertions only (in addition contracts of public, protected, and private members can only use other public, public/protected, and public/protected/private members respectively).] [No, assertions only (in addition only public members can be used in preconditions).] [Yes.] ][ [['Constant-correctness]] [No, enforced only for class invariants and old values (making also preconditions and postconditions constant-correct is possible but requires users to program a fare amount of boiler-plate code).] [Yes.] - [Yes.] + [Yes (side effects in contracts lead to undefined behaviour).] [Yes.] [No, enforced only for class invariants.] ][ @@ -492,14 +500,13 @@ 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 [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 also [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]). -However, that possibility is limited to contract checking when an incorrect argument will simply fail the contract and call the related contract failure handler as expected anyway. -In any case, because of that __N1962__ does not disable any assertion while checking preconditions. -That makes it possible to have infinite recursion while checking preconditions so Eiffel disables assertion checking also while checking preconditions. -Therefore, this library by default disables assertion checking also while checking preconditions, but it also provides the [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] configuration macro so users can change this behaviour to match __N1962__ if needed. +Technically, it can be shown that an invalid argument can reach the function body when assertion checking is disabled while checking preconditions (that is why __N1962__ does not disable any assertion while checking preconditions, see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). +However, this can only happen while checking contracts when an invalid argument passed to the body, which should results in the body either throwing an exception or returning an incorrect result, will in turn fail the contract assertion being checked by the caller of the body and invoke the related contract failure handler as desired in the first place. +Furthermore, not disabling assertions while checking preconditions (like __N1962__ does) makes it possible to have infinite recursion while checking preconditions. +Therefore, this library by default disables assertion checking also while checking preconditions (like Eiffel does), but it also provides the [macroref BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION] configuration macro so users can change this behaviour to match __N1962__ if needed. ] (In multi-threaded programs this introduces a global lock, see [macroref BOOST_CONTRACT_DISABLE_THREADS].) ] @@ -514,7 +521,7 @@ Disable nothing. [footnote *Rationale:* Older versions of this library defined a data member in the user class that was automatically used to disable checking of class invariants within nested member function calls (similarly to Eiffel). -This feature was required by older revisions of __N1962__ but it is no longer required in __N1962__ (because it seems to be motivated purely by optimization reasons while similar performances can be achieved by disabling invariants for release builds). +This feature was required by older revisions of __N1962__ but it is no longer required by __N1962__ (because it seems to be motivated purely by optimization reasons while similar performances can be achieved by disabling invariants for release builds). Furthermore, in multi-threaded programs this feature would introduce a lock that synchronizes all member functions calls for a given object. Therefore, this feature was removed in the current revision of this library. ] @@ -525,7 +532,7 @@ Therefore, this feature was removed in the current revision of this library. [Disable nothing.] ][ [['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 macros shown in __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 also possible but requires using macros as shown in __Disable_Contract_Compilation__).] [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).] @@ -540,7 +547,7 @@ Therefore, this feature was removed in the current revision of this library. ] ] -The authors of this library consulted the following references that implement contract programming for C++ (but usually for only a limited set of features, or using preprocessing tools other than the C++ preprocessor and external to the language itself) and for other languages (see __Bibliography__ for a complete list of all the references consulted during the design and development of this library): +The authors of this library consulted the following references that implement contract programming for C++ (but usually for only a limited set of features, or using preprocessing tools other than the C++ preprocessor and external to the language itself) and for other languages (see __Bibliography__ for a complete list of all references consulted during the design and development of this library): [table [ [Reference] [Language] [Notes] ] @@ -593,22 +600,34 @@ 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++ (without using preprocessing tools external to the language itself): +To the best knowledge of the authors, this the only library that fully supports all contract programming features for C++ (without using preprocessing tools external to the language itself). +In general: * 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. +* 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 pseudocode attempts to emulate old values using __P0380__ (`scope_exit` here is an RAII object that executes the nullary functor passed to its constructor when it is destroyed): +For example, the following pseudocode attempts to emulate old values in __P0380__: `` + struct scope_exit { // RAII. + template + explicit scope_exit(F f) : f_(f) {} + ~scope_exit() { f_(); } + + scope_exit(scope_exit const&) = delete; + scope_exit& operator=(scope_exit const&) = delete; + private: + std::function f_; + }; + void fswap(file& x, file& y) [[expects: x.closed()]] - [[excepts: y.closed()]] - // Postconditions in function definition below to emulate old values. + [[expects: y.closed()]] + // Cannot use [[ensures]] for postconditions so to emulate old values. { file old_x = x; // Emulate old values with local copies (not disabled). file old_y = y; scope_exit ensures([&] { // Check after local objects destroyed. - if(!std::uncaught_exception()) { // Check only if no throw. + if(std::uncaught_exceptions() == 0) { // Check only if no throw. [[assert: x.closed()]] [[assert: y.closed()]] [[assert: x == old_y]] @@ -620,22 +639,22 @@ For example, the following pseudocode attempts to emulate old values using __P03 scope_exit close_x([&] { x.close(); }); y.open(); scope_exit close_y([&] { y.close(); }); - file t = file::temp(); - t.open; - scope_exit close_t([&] { t.close(); }); + file z = file::temp(); + z.open; + scope_exit close_z([&] { z.close(); }); - x.mv(t); + x.mv(z); y.mv(x); - t.mv(y); + z.mv(y); } `` This requires boiler-plate code to make sure postconditions are correctly checked only if the function did not throw an exception and in a `scope_exit` RAII object after all other local objects have been destroyed (because some of these destructors contribute to establishing the postconditions). -Still, it never disables old value copies (not even if postconditions are disabled in release builds). +Still, it never disables old value copies (not even if postconditions are disabled in release builds, this would require adding even more boiler-plate code using `#ifdef`, etc.). ] * Implementing class invariants is more involved (especially if done automatically, without requiring programmers to manually invoke extra functions to check the invariants). [footnote -For example, the following pseudocode attempts to emulation of class invariants using __P0380__: +For example, the following pseudocode attempts to emulation of class invariants in __P0380__: `` template class vector { @@ -671,7 +690,7 @@ This requires boiler-plate code to manually invoke the function that checks the In case the destructor can throw (e.g., it is declared `noexcept(false)`), the destructor also requires a `try-catch` statement similar to the one programmed for `push_back` to check class invariants at destructor exit when it throws exceptions. Still, an outstanding issue remains to avoid infinite recursion if also `empty` and `size` are public functions programmed to check class invariants (because __P0380__ does not automatically disable assertions while checking other assertions). ] -All references reviewed by the authors seem to not consider static and volatile functions not supporting static and volatile invariants respectively. +In addition, 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/examples.qbk b/doc/examples.qbk index ed7941d9..5e83ba19 100644 --- a/doc/examples.qbk +++ b/doc/examples.qbk @@ -10,7 +10,7 @@ This section lists some examples taken from different sources discussing contrac [note Some of these examples might be from old code, containing obsolete coding practices, not optimized for execution speed, not complete, and they might be more relevant in the context of programming languages different from C++. -Nevertheless, programmers are encouraged to review these examples to see a few diverse usages of this library that might be relevant to their needs. +Nevertheless, programmers are encouraged to review these examples to see a few diverse uses of this library that might be relevant to their needs. ] Sources of the listed examples: diff --git a/doc/extras.qbk b/doc/extras.qbk index c9018889..28fb989c 100644 --- a/doc/extras.qbk +++ b/doc/extras.qbk @@ -18,13 +18,13 @@ In these cases, programmers can declare old values using [classref boost::contra However, in some other cases it might be desirable to simply skip assertions that use old values when the respective old value types are not copyable, without causing compile-time errors. Programmers can do this using [classref boost::contract::old_ptr_if_copyable] instead of [classref boost::contract::old_ptr] and 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 [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +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 only for 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). -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__ (using the `oldof(...)` syntax) and that C++17 `if constexpr` can be used within __P0380__ contracts: +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 old values (so compiling the code with and without contracts will not necessarily alter the type requirements of the program). +Something similar could be achieved combing C++17 `if constexpr` with __N1962__ or __P0380__ so that old value expressions within template code can 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__ (using some kind of `oldof(...)` syntax) and that C++17 `if constexpr` can be used within __P0380__ contracts: `` template void offset(T& x, int count) @@ -37,22 +37,46 @@ For example, assuming old values are added to __P0380__ (using the `oldof(...)` [old_if_copyable_offset] The old value pointer `old_x` is programmed using [classref boost::contract::old_ptr_if_copyable]. -When `T` is copyable, this `boost::contract::old_ptr_if_copyable]` behaves like `boost::contract::old_ptr`. -When `T` is not copyable instead, `boost::contract::old_ptr_if_copyable` will simply not copy `x` at run-time and leave `old_x` initialized as a null pointer. -Therefore, [classref boost::contract::old_ptr_if_copyable] objects like `old_x` must be checked to be not null as in `if(old_x) ...` before they are dereferenced in postconditions and exception guarantees. +When `T` is copyable, [classref boost::contract::old_ptr_if_copyable]`` behaves like [classref boost::contract::old_ptr]``. +When `T` is not copyable instead, [classref boost::contract::old_ptr_if_copyable]`` will simply not copy `x` at run-time and leave `old_x` initialized to a null pointer. +Therefore, [classref boost::contract::old_ptr_if_copyable] objects like `old_x` must be checked to be not null as in `if(old_x) ...` before they are dereferenced in postconditions and exception guarantees (to avoid run-time errors of dereferencing null pointers). -If the above example used [classref boost::contract::old_ptr] instead then this 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.). +If the above example used [classref boost::contract::old_ptr] instead then this 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, for example in the contract assertions using `*old_x ...` or `old_x->...`). +[footnote +Technically, on C++17 it is possible to use [classref boost::contract::old_ptr] together with `if constexpr` instead of using [classref boost::contract::old_ptr_if_copyable], for example: +`` + template + void offset(T& x, int count) { + boost::contract::old_ptr old_x; + if constexpr(boost::contract::is_old_value_copyable::value) old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::check c = boost::contract::function() + .postcondition([&] { + if constexpr(boost::contract::is_old_value_copyable::value) BOOST_CONTRACT_ASSERT(x == *old_x + count); + }) + ; + + x += count; + } +`` +However, the authors find this code less readable and more verbose than its equivalent that uses [classref boost::contract::old_ptr_if_copyable]. +Guarding old value copies and related assertions with `if constexpr` is useful instead when the guard condition checks type requirements more complex than just [classref boost::contract::is_old_value_copyable] (as shown later in this documentation). +] 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 its type requirements are more stringent than [classref boost::contract::old_ptr_if_copyable]). -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 statements are equivalent: auto old_x = BOOST_CONTRACT_OLDOF(x); // C++11 auto declarations always use `old_ptr` (never `old_ptr_if_copyable`). boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); +If programmers want to relax the copyable type requirement, they must do so explicitly by using the [classref boost::contract::old_ptr_if_copyable] type instead of using `auto` declarations. + +[heading Old Value Type Traits] + This library 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. + +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] @@ -63,12 +87,9 @@ On the flip side, the following specializations of [classref boost::contract::is [old_if_copyable_p_decl] [old_if_copyable_p_spec] -[heading No C++11] - -In general, `boost::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 [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +In general, `boost::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 copyable or not. +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), or just specialize [classref boost::contract::is_old_value_copyable]. +For example, for a non-copyable type `n` the following code will work also on non-C++11 compilers (see [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [old_if_copyable_n_decl] [old_if_copyable_n_spec] @@ -83,21 +104,20 @@ Some of these type requirements might be necessary only to check the assertions 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 some other cases it might be desirable to not augment the type requirements of a program because of contract assertions and to simply skip these assertions when user types do not provide all the operations necessary to check them, without causing compile-time errors. -Programmers can do this using [funcref boost::contract::condition_if] (or [funcref boost::contract::condition_if_c]). +However, in some other cases it might be desirable to not augment the type requirements of a program just because of contract assertions and to simply skip assertions when user types do not provide all the operations necessary to check them, without causing compile-time errors. +Programmers can do this using `if constexpr` on C++17 compilers, and [funcref boost::contract::condition_if] (or [funcref boost::contract::condition_if_c]) on non-C++17 compilers. For example, let's consider the following `vector` class template equivalent to `std::vector`. C++ `std::vector` does not require that its value type parameter `T` has an equality operator `==` (it only requires `T` to be copy constructible, see `std::vector` documentation). 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). -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. +Otherwise, programmers can guard this postcondition using C++17 `if constexpr` to evaluate the asserted condition only for types `T` that have an equality operator `==` and skip it otherwise. [footnote *Rationale:* __N1962__ and other proposals to add contracts to C++ do not provide a mechanism to selectively disable assertions based on their type requirements. -However, this library provides such a mechanism to allow to program contracts for template code without necessarily adding extra type requirements that would not be present if it was not for the contracts (so compiling the code with and without contracts will not necessarily alter the type requirements of the program). -Something similar could be achieved combing C++17 `if constexpr` with __N1962__ or __P0380__ so that contract assertions within template code could be guarded by `if constexpr` statements checking related type requirements (__N1962__ already supports `if` statements under the name of /select assertions/, __P0380__ does not so probably `if` statements should be added to __P0380__ as well). -For example, assuming old values are added to __P0380__ (using the `oldof(...)` syntax) and that C++17 `if constexpr` can be used within __P0380__ contracts: +However, this library provides such a mechanism to allow to program contracts for template code without necessarily adding extra type requirements that would not be present if it was not for the contracts (so compiling the code with and without contracts will not alter the type requirements of the program). +Something similar could be achieved combing C++17 `if constexpr` with __N1962__ or __P0380__ so that contract assertions within template code could be guarded by `if constexpr` statements checking the related type requirements (__N1962__ already allows of `if` statements in contracts under the name of /select assertions/, __P0380__ does not so probably `if` statements should be added to __P0380__ as well). +For example, assuming C++17 `if constexpr` can be used within __P0380__ contracts: `` template class vector { @@ -108,36 +128,38 @@ For example, assuming old values are added to __P0380__ (using the `oldof(...)` }; `` ] -For example (see [@../../example/features/condition_if.cpp =condition_if.cpp=]): - -[import ../example/features/condition_if.cpp] -[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); - } +For example: + 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); + } + /* ... */ +More in general, `if constexpr` can be used to guard a mix of both old value copies and contract assertions that introduce specific extra type requirements. +For example, the following `swap` function can be called on any type `T` that is movable but its old value copies and postcondition assertions are evaluated only for types `T` that are also copyable and have an equality operator `==` (see [@../../example/features/if_constexpr.cpp =if_constexpr.cpp=]): +[import ../example/features/if_constexpr.cpp] +[if_constexpr] +[heading No `if constexpr` (no C++17)] +On non-C++17 compilers where `if constexpr` is not available, it is possible to use [funcref boost::contract::condition_if] to skip assertions based on type requirements (even if this code is less readable and more verbose than using `if constexpr`). +For example (see [@../../example/features/condition_if.cpp =condition_if.cpp=]): - /* ... */ -``]] -] +[import ../example/features/condition_if.cpp] +[condition_if] More in general, [funcref boost::contract::condition_if] is used as follow: @@ -146,15 +168,15 @@ More in general, [funcref boost::contract::condition_if] is used as follow: ) Where `Pred` is a nullary boolean meta-function and `cond` is a nullary boolean functor. -If `Pred::value` is statically evaluated to be `true` at compile-time then `cond()` is called at run-time and its boolean result is returned by the enclosing [classref boost::contract::condition_if] call. -Otherwise, if `Pred::value` is statically evaluated to be `false` at compile-time then [classref boost::condition_if] trivially returns `true`. -Therefore, if `cond` is a functor template instantiation (not just a functor) then its call that contains the assertion operations with the extra type requirements (e.g., the equality operator `==`) will not be actually instantiated and compiled unless the compiler determines at compile-time that `Pred::value` is `true` (functor templates like `std::equal_to` and C++14 generic lambdas can be used to program `cond`, but C++11 lambdas cannot). +If `Pred::value` is statically evaluated to be `true` at compile-time then `cond()` is called at run-time and its boolean result is returned by the enclosing [funcref boost::contract::condition_if] call. +Otherwise, if `Pred::value` is statically evaluated to be `false` at compile-time then [funcref boost::contract::condition_if] trivially returns `true`. +Therefore, if `cond` is a functor template instantiation (not just a functor) then its call that contains the assertion operations with the extra type requirements (e.g., the equality operator `==`) will not be actually instantiated and compiled unless the compiler determines at compile-time that `Pred::value` is `true` (when used this way, functor templates like `std::equal_to` and C++14 generic lambdas can be used to program `cond`, but C++11 lambdas cannot). -The [funcref boost::contract::condition_if] function template is a special case of the more general [funcref boost::contract::call_if], specifically `boost::contract::condition_if(cond)` is equivalent to `boost::contract::call_if(cond).else_([] { return true; })`. +The [funcref boost::contract::condition_if] function template is a special case of the more general [funcref boost::contract::call_if], specifically [funcref boost::contract::condition_if]`(cond)` is logically equivalent to [funcref boost::contract::call_if]`(cond).else_([] { return true; })`. [footnote -For optimization reasons, the internal implementation of [funcref boost::contract::condition_if] does not actually use [funcref boost::contract::call_if]. +The internal implementation of [funcref boost::contract::condition_if] is optimized and it does not actually use [funcref boost::contract::call_if]. ] -The [funcref boost::contract::call_if] function template accepts a number of optional /else-if/ statements and one optional /else/ statement: +The [funcref boost::contract::call_if] function template also accepts a number of optional /else-if/ statements and one optional /else/ statement: boost::contract::call_if( t1 @@ -167,29 +189,23 @@ The [funcref boost::contract::call_if] function template accepts a number of opt ) Where `Pred1`, `Pred2`, ... are nullary boolean meta-functions and `t1`, `t2`, ..., `e` are nullary functors. -The return types of the functor calls `t1()`, `t2()`, ..., `e()` must either be all the same (possibly all `void`) or be of types implicitly convertible into one another. +The return types of the functor calls `t1()`, `t2()`, ..., `e()` must either be all the same (including possibly all `void`) or be of types implicitly convertible into one another. At run-time [funcref boost::contract::call_if] will call the functor `t1()`, or `t2()`, ..., or `e()` depending on which meta-function `Pred1::value`, `Pred2::value`, ... is statically evaluated to be `true` or `false` at compile-time, and it will return the value returned by the functor being called. -If `t1`, `t2`, ..., `e` are nullary functor template instantiations (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 `Pred1::value`, `Pred2::value`, ... are respectively evaluated to be `true` or `false` at compile-time). +If `t1`, `t2`, ..., `e` are functor template instantiations (not just 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 `Pred1::value`, `Pred2::value`, ... are respectively 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`, otherwise it is required. +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 seen so far, but they take their predicate 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). +[import ../example/features/call_if_cxx14.cpp] On compilers that support C++17 `if constexpr` there should be no need to use [funcref boost::contract::condition_if] or [funcref boost::contract::call_if] because `if constexpr` can be used instead (making the code more readable and easier to program). - -[heading If-Constexpr Emulation (C++14)] - -A part from its use within contracts, on C++14 compilers [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to emulate C++17 `if constexpr`. [footnote -Boost.Hana (`boost::hana::if_`) and probably other approaches can also be used together with generic lambdas to emulate C++17 `if constexpr` on C++14 compilers. -] -For example (see [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): - -[import ../example/features/call_if_cxx14.cpp] -[table -[[Until C++17 (without `if constexpr`)][Since C++17 (with `if constexpr`)]] -[[[call_if_cxx14]] [`` +A part from its use within contracts, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to emulate C++17 `if constexpr` (`boost::hana::if_` and probably other approaches can also be used together with generic lambdas to emulate C++17 `if constexpr` on C++14 compilers). +For example, the following implementation of `myadvance` will compile since C++14 and it is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching (see [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): +[call_if_cxx14] +Of course, since C++17 the implementation that uses `if constexpr` is even more readable and concise: +`` template void myadvance(Iter& i, Dist n) { if constexpr(is_random_access_iterator::value) { @@ -198,17 +214,14 @@ void myadvance(Iter& i, Dist n) { if(n >= 0) while(n--) ++i; else while(n++) --i; } else if constexpr(is_input_iterator::value) { - while(n--) ++p; + while(n--) ++i; } 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] [section Volatile Public Functions] @@ -245,7 +258,7 @@ Note that while all public functions can be made to check `const volatile` invar That is because both `const` and `volatile` can always be added but never stripped in C++ (a part from forcefully via `const_cast`) but `const` is always automatically added by this library in order to enforce contract constant-correctness (see __Constant_Correctness__). That said, it would be too stringent for this library to also automatically add `volatile` and require all functions to check `const volatile` (not just `const`) invariants because only `volatile` members can be accessed from `const volatile` invariants so there could be many `const` (but not `const volatile`) members that are accessible from `const` invariants but not from `const volatile` invariants. To avoid this confusion, this library has chosen to draw a clear dichotomy between `const` and `const volatile` invariants so that only volatile public functions check `const volatile` invariants and only non-volatile public functions check `const` (but not `const volatile`) invariants. -This is simple and should serve most cases. +This is a clear distinction and it should serve most cases. If programmers need non-volatile public functions to also check `const volatile` invariants, they can explicitly do so by calling the `const volatile` invariant function from the `const` invariant function as shown in this documentation. ] @@ -254,7 +267,7 @@ If programmers need non-volatile public functions to also check `const volatile` void invariant() const volatile { ... } // Volatile invariants. void invariant() const { - const_cast(this)->invariant(); // Call `const volatile` invariant function above. + auto const volatile* cv = this; cv->invariant(); // Call `const volatile` invariant function above. ... // Other non-volatile invariants. } diff --git a/doc/full_table_of_contents.qbk b/doc/full_table_of_contents.qbk index e37f2d3f..98af9888 100644 --- a/doc/full_table_of_contents.qbk +++ b/doc/full_table_of_contents.qbk @@ -48,7 +48,7 @@ __Advanced__ __Function_Overloads__ __Lambdas_Loops_Code_Blocks_and_constexpr__ __Implementation_Checks__ - __Old_Value_Copies_at_Body__ + __Old_Values_Copied_at_Body__ __Named_Overrides__ __Access_Specifiers__ __Throw_on_Failures_and_noexcept__ diff --git a/doc/getting_started.qbk b/doc/getting_started.qbk index 49dc1815..bdb4b3b1 100644 --- a/doc/getting_started.qbk +++ b/doc/getting_started.qbk @@ -43,6 +43,7 @@ This library has been developed and tested using: * Clang version 3.8.1 on Cygwin (with C++11 features enabled =-std=c++11=). For information on other compilers and platforms see the library [@http://www.boost.org/development/tests/master/developer/contract.html regression tests]. +The development and maintenance of this library is hosted on [@https://github.com/boostorg/contract GitHub]. [endsect] diff --git a/doc/main.qbk b/doc/main.qbk index c9914a0f..c591f033 100644 --- a/doc/main.qbk +++ b/doc/main.qbk @@ -62,7 +62,7 @@ [def __Lambdas_Loops_Code_Blocks__ [link boost_contract.advanced.lambdas__loops__code_blocks__and__constexpr__ Lambdas, Loops, Code Blocks]] [def __Lambdas_Loops_Code_Blocks_and_constexpr__ [link boost_contract.advanced.lambdas__loops__code_blocks__and__constexpr__ Lambdas, Loops, Code Blocks (and `constexpr`)]] [def __Implementation_Checks__ [link boost_contract.advanced.implementation_checks Implementation Checks]] -[def __Old_Value_Copies_at_Body__ [link boost_contract.advanced.old_value_copies_at_body Old Value Copies at Body]] +[def __Old_Values_Copied_at_Body__ [link boost_contract.advanced.old_values_copied_at_body Old Values Copied at Body]] [def __Named_Overrides__ [link boost_contract.advanced.named_overrides Named Overrides]] [def __Access_Specifiers__ [link boost_contract.advanced.access_specifiers Access Specifiers]] [def __Throw_on_Failures__ [link boost_contract.advanced.throw_on_failures__and__noexcept__ Throw on Failures]] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 7feb542e..a3497337 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -6,7 +6,7 @@ [section Tutorial] -This section is a guide to basic usages of this library. +This section is a guide to basic usage of this library. [section Non-Member Functions] @@ -23,16 +23,16 @@ It is possible to specify preconditions, postconditions, and exception guarantee The [funcref boost::contract::function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). [footnote -The name of this local variable is arbitrary, but `c` is often used in this documentation for ["c]heck or ["c]aminiti [^;-)]. +The name of this local variable is arbitrary, but `c` is often used in this documentation for ["c]heck or ["c]aminiti [^;-)] . ] Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). [footnote *Rationale:* -C++17 guaranteed copy elision on function return values removes the trick this library uses to force a compile-time error when `auto` is incorrectly used instead of [classref boost::contract::check]. +C++17 guaranteed copy elision on function return value voids the trick this library uses to force a compile-time error when `auto` is incorrectly used instead of [classref boost::contract::check]. The library still generates a run-time error in this case (also on C++17). In any case, after reading this documentation it should be evident to programmers that `auto` should not be used in [classref boost::contract::check] declarations so this misuse of `auto` should not be an issue in practice. ] -The function body is programmed right after the declaration of the RAII object. +The function body is programmed right after the declaration of this RAII object. [note In some cases, it might be necessary to program some code before the contract. @@ -61,7 +61,7 @@ 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 parameters as [^['r]]`()`. +When preconditions are specified, they are programmed using a functor [^['r]] passed to `.precondition(`[^['r]]`)` that can be called with no parameters as in [^['r]]`()`. Contracts that do not have preconditions simply do not call `.precondition(...)`. Preconditions must appear before postconditions and exception guarantees when these are all present (see __Postconditions__ and __Exception_Guarantees__). @@ -89,16 +89,16 @@ These variables can be captured by value when the overhead of copying such varia [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__). +In any case, programmers should not write precondition assertions that 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 that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program precondition assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if `bool_cond` contains commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` contains commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call the failure handler [funcref boost::contract::precondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if calling the functor specified via `.precondition(...)` throws any exception. +This library will automatically call the failure handler [funcref boost::contract::precondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false or, more in general, if calling the functor specified via `.precondition(...)` throws any exception. By default, this failure handler prints an error message to `std::cerr` and terminates the program calling `std::terminate` (see __Throw_on_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). [note @@ -111,7 +111,7 @@ However, this library does not enforce such a constraint and it leaves it up to [section Postconditions] -When postconditions are specified, they are programmed using a functor [^['s]] passed to `.postcondition(`[^['s]]`)` that can be called with no parameters as [^['s]]`()`. +When postconditions are specified, they are programmed using a functor [^['s]] passed to `.postcondition(`[^['s]]`)` that can be called with no parameters as in [^['s]]`()`. Contracts that do not have postconditions simply do not call `.postcondition(...)`. Postconditions must appear after preconditions but before exception guarantees when these are all present (see __Preconditions__ and __Exception_Guarantees__). @@ -131,22 +131,22 @@ For example, for [funcref boost::contract::function] (similarly for all other co ... } -The postcondition functor should capture all variables that it needs to assert the postconditions. -In general, these variables should be captured by reference and not by value (because postconditions need to access the value that these variables will have at function exit, and not the value these variables had when the postcondition functor was first constructed). +The postcondition functor should capture all the variables that it needs to assert the postconditions. +In general, these variables should be captured by reference and not by value (because postconditions need to access the value that these variables will have at function exit, and not the value these variables had when the postcondition functor was first declared). Postconditions can also capture return and old values (see __Return_Values__ and __Old_Values__). -In any case, postcondition assertions should not modify the value of the captured variables (see __Constant_Correctness__). +In any case, programmers should not write postcondition assertions that modify the value of the captured variables, even when those are captured by reference (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 that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program postcondition assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call the failure handler [funcref boost::contract::postcondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if calling the functor specified via `.postcondition(...)` throws any exception. +This library will automatically call the failure handler [funcref boost::contract::postcondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false or, 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_Failures__ to change the failure handler to throw exceptions, exit the program with an error code, etc.). -For non-void virtual public functions and public function overrides, the functor [^['s]] passed to `.postcondition(`[^['s]]`)` is not a nullary functor, instead it is a unary functor taking a variable holding the return value as its one parameter [^['s]]`(`[^['result]]`)` (this is to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). +For non-void virtual public functions and non-void 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] @@ -164,27 +164,30 @@ For example, for [funcref boost::contract::function] (similarly for all other co boost::contract::check c = boost::contract::function() // Same for all other contracts. ... .postcondition([&] { // Also capture `result` reference... - BOOST_CONTRACT_ASSERT(result ...); // ...but should not modify captures. + BOOST_CONTRACT_ASSERT(result == ...); // ...but should not modify captures. ... }) ... ; - ... // Assign `result` at each return. + ... + return result = ...; // Assign `result` at each return. } At any point where the enclosing function returns, programmers are responsible to assign the result variable to the expression being returned. This can be done ensuring that /all/ `return` statements in the function are of the form: - return result = return_expr; // Assign `result` at each return. + ``[^['return-type]]`` result; + ... + return result = ``[^['return-expression]]``; // Assign `result` at each return. -The functor used to program postconditions should capture the result variable by reference and not by value (because postconditions must access the value the result variable will have at function exit, and not the value the result variable had when the postcondition functor was first constructed). +The functor used to program postconditions should capture the result variable by reference and not by value (because postconditions must access the value the result variable will have at function exit, and not the value the result variable had when the postcondition functor was first declared). The return value should never be used in preconditions, old value copies, or exception guarantees (because the return value is not yet correctly evaluated and set when preconditions are checked, old values are copied, or if the function throws an exception). In any case, programmers should not modify the result variable in the contract assertions (see __Constant_Correctness__). It is also possible to declared the result variable using `boost::optional` when the function return type does not have a default constructor, or if the default constructor is too expensive or undesirable to execute when first declaring the result variable (see __Optional_Return_Values__). -Non-void virtual public functions and public function overrides must always declare and use a result variable even when postconditions do not directly use the function return value (this is to properly support subcontracting, see __Virtual_Public_Functions__ and __Public_Function_Overrides__). +Non-void virtual public functions and non-void 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] @@ -202,7 +205,7 @@ For example, for [funcref boost::contract::function] (similarly for all other co boost::contract::check c = boost::contract::function() // Same for all other contracts. ... // Preconditions shall not use old values. .postcondition([&] { // Capture by reference... - BOOST_CONTRACT_ASSERT(*old_var ...); // ...but should not modify captures. + BOOST_CONTRACT_ASSERT(*old_var == ...); // ...but should not modify captures. ... }) .except([&] { // Capture by reference... @@ -218,7 +221,7 @@ Old values are handled by this library using the smart pointer class template [c [footnote *Rationale:* Old values have to be optional values because they need to be left uninitialized when they are not used because both postconditions and exception guarantees are disabled (defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS]). -That is to avoid old value copies when old values are not used, so a pointer, or better a `boost::optional`, could have been used for that. +That is to avoid old value copies when old values are not used, either a pointer or (better) a `boost::optional` could have been used to achieve 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 type is automatically qualified as `const` (so old values cannot be mistakenly changed by contract assertions, see __Constant_Correctness__). @@ -226,12 +229,12 @@ This library ensures that old value pointers are always not null by the time pos 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], but also when checking an overridden virtual public function contract via subcontracting, etc. +For example, old value pointers might be null in preconditions when postconditions and exception guarantees are disabled defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS] (but also when checking an overridden virtual public function contract via subcontracting, etc.). ] -See __Old_Value_Copies_at_Body__ for delaying the copy 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). +See __Old_Values_Copied_at_Body__ for delaying the copy of old values until after class invariants (for constructors, destructors, and public functions) and preconditions are checked (when necessary, this allows to program old value expressions under the simplifying assumption that class invariant and precondition assertions are satisfied already). [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])]. +C++11 auto declarations can be used with [macroref BOOST_CONTRACT_OLDOF] for brevity `auto `[^old_['variable-name] = BOOST_CONTRACT_OLDOF(['expression])] (but see also __Old_Value_Requirements__). See __No_Macros__ to program old values without using [macroref BOOST_CONTRACT_OLDOF] (e.g., on compilers that do not support variadic macros). [note @@ -243,7 +246,7 @@ 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 parameters as [^['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 in [^['e]]`()`. Contracts that do not have exception guarantees simply do not call `.except(...)`. Exception guarantees must appear after both preconditions and postconditions when these are all present (see __Preconditions__ and __Postconditions__). @@ -262,25 +265,25 @@ For example, for [funcref boost::contract::function] (similarly for all other co ... } -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 function return value instead (because the return value will not be properly set when the function throws an exception). -In any case, exception guarantee assertions should not modify the value of the captured variables (see __Constant_Correctness__). +The exception guarantee functor should capture all the 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 declared). +Exception guarantees can also capture old values (see __Old_Values__) but they should not access the function return value instead (because the return value is not be properly set when the function throws an exception). +In any case, programmers should not write exception guarantee assertions that modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__). [note In real production code, it might be difficult to program meaningful exception guarantees without resorting to expensive old value copies that will slow down execution. Therefore, the authors recognize that exception guarantees, even if supported by this library, might not be used often in practice (and they are not used in most of the examples listed in the rest of this documentation). -In any case, these performance considerations are ultimately left to programmers and their specific application domain. +In any case, these performance considerations are ultimately left to programmers and their specific application domains. ] 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 that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program exception guarantee assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call the failure handler [funcref boost::contract::except_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if calling the functor specified via `.except(...)` throws any exception. +This library will automatically call the failure handler [funcref boost::contract::except_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false or, 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_Failures__ to change the failure handler to exit the program with an error code or to take some other custom action). [note @@ -293,11 +296,11 @@ Therefore, programmers should not change the exception guarantee failure handler [section Class Invariants] -Public member functions, constructors, and destructors can be programmed to check class invariants. +Public member functions, constructors, and destructors can be programmed to also check class invariants. When class invariants are specified, they are programmed in a public `const` function named `invariant` taking no argument and returning `void`. Classes that do not have invariants, simply do not declare the `invariant` function. [footnote -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]. +This library uses template meta-programming (SFINAE-based introspection techniques) to check invariants only for classes that declare a member function named by [macroref BOOST_CONTRACT_INVARIANT_FUNC]. ] For example: @@ -315,13 +318,13 @@ This member function must be `const` because contracts should not modify the obj This library will generate a compile-time error if the `const` qualifier is missing (unless [macroref BOOST_CONTRACT_PERMISSIVE] is defined). Any code can be programmed in the `invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex invariants that might be buggy and slow to check at run-time). -It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program class invariant assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program class invariant assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if `bool_cond` has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call failure handlers [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if the `invariant` function throws an exception when invariants are checked at function entry or exit respectively. +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 or, 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_Failures__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). See __Access_Specifiers__ to avoid making the `invariant` member function `public`. @@ -344,7 +347,7 @@ Static public functions can be programmed to check static class invariants. When static class invariants are specified, they are programmed in a public `static` function named `static_invariant` taking no argument and returning `void`. Classes that do not have static class invariants, simply do not declare the `static_invariant` function. [footnote -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]. +This library uses template meta-programming (SFINAE-based introspection techniques) to check static invariants only for classes that declare a member function named by [macroref BOOST_CONTRACT_STATIC_INVARIANT_FUNC]. ] For example: @@ -362,13 +365,13 @@ 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 that enables this library to print informative error messages when the asserted conditions are evaluated to be false (this is not a variadic macro, see __No_Macros__): +It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program the assertions because that enables this library to print informative error messages when the asserted conditions are evaluated to be false (note that this is not a variadic macro, see __No_Macros__): - BOOST_CONTRACT_ASSERT(bool_cond) - // Or, if condition has commas `,` not already within parenthesis `()`... - BOOST_CONTRACT_ASSERT((bool_cond)) // ...use extra parenthesis (not a variadic macro). + BOOST_CONTRACT_ASSERT(``[^['boolean-condition]]``) + // Or, if `boolean-condition` has commas `,` not already within parenthesis `()`... + BOOST_CONTRACT_ASSERT((``[^['boolean-condition]]``)) // ...use extra parenthesis (not a variadic macro). -This library will automatically call failure handlers [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are false and, more in general, if the `static_invariant` function throws an exception when invariants are checked at function entry or exit respectively. +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 or, 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_Failures__ to change these failure handlers to throw exceptions, exit the program with an error code, etc.). See __Access_Specifiers__ to avoid making `static_invariant` member function `public`. @@ -396,7 +399,7 @@ For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_end] It is not possible to specify preconditions using `.precondition(...)` for constructors (this library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]). -Constructor preconditions are specified using the [classref boost::contract::constructor_precondition] base class instead (but considerations from __Preconditions__ apply also to the precondition functor passed to [classref boost::contract::constructor_precondition]). +Constructor preconditions are specified using the [classref boost::contract::constructor_precondition] base class instead (same considerations as the ones made in __Preconditions__ apply also to the precondition functor passed to [classref boost::contract::constructor_precondition]). Programmes should not access the object `*this` from constructor preconditions (because the object does not exists yet before the constructor body is executed). [footnote See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). @@ -410,10 +413,10 @@ On MSVC compilers with that bug, an extra (static) member function can be used ( * 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 its derived classes). -* It takes the derived class as template parameter (the Curiously Recursive Template Pattern (CRTP) is used here to avoid ambiguity resolution errors with multiple inheritance). +* It takes the derived class as template parameter. [footnote *Rationale:* -The [classref boost::contract::constructor_precondition] takes the derived class as its template parameter so the instantiated template type is unique for each derived class. +The [classref boost::contract::constructor_precondition] takes the derived class as its template parameter (using the Curiously Recursive Template Pattern, CRTP) so the instantiated template type is unique for each derived class. This always avoids base class ambiguity resolution errors even when multiple inheritance is used. Note that virtual inheritance could not be used instead of the template parameter here to resolve ambiguities (because virtual bases are initialized only once by the outer-most derived class, and that would not allow to properly check preconditions of all base classes). ] @@ -426,7 +429,7 @@ It is possible to specify postconditions for constructors (see __Postconditions_ [footnote See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). ] -It is also possible to specify exceptions guarantees for constructors (see __Exception_Guarantees__), but programmers should not access the object `this` or its old value in constructor exception guarantees (because the object did not exist before executing the constructor body and it was not properly constructed given the constructor body threw an exception). +It is also possible to specify exceptions guarantees for constructors (see __Exception_Guarantees__), but programmers should not access the object `*this` or its old value in constructor exception guarantees (because the object did not exist before executing the constructor body and it was not properly constructed given the constructor body threw an exception). [footnote See __No_Lambda_Functions__ to enforce these constraints at compile-time (but not recommended because of extra boiler-plate code). ] @@ -434,7 +437,7 @@ The [funcref boost::contract::constructor] function takes `this` as a parameter 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 prior C++17 and a run-time error post C++17). -The constructor body is programmed right after the declaration of the RAII object. +The constructor body is programmed right after the declaration of this RAII object. At construction, the [classref boost::contract::check] RAII object for constructors does the following (enclosing constructor entry): @@ -459,6 +462,8 @@ Therefore, unless these constructors are not public or they have no precondition Similar considerations apply to all other constructors automatically generated by C++ (e.g., the move constructor). ] +[heading Private and Protected Constructors] + 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: @@ -503,19 +508,19 @@ For example (see [@../../example/features/public.cpp =public.cpp=]): [public_class_end] It is not possible to specify preconditions for destructors (this library will generate a compile-time error if `.precondition(...)` is used here and that is because destructors can be called at any time after construction so they have no precondition). -It is possible to specify postconditions for destructors (see __Postconditions__, and also __Static_Public_Functions__ for an example), but programmers should not access the object `this` in destructor postconditions (because the object no longer exists after the destructor body has been executed). +It is possible to specify postconditions for destructors (see __Postconditions__, and also __Static_Public_Functions__ for an example), but programmers should not access the object `*this` in destructor postconditions (because the object no longer exists after the destructor body has been executed). [footnote See __No_Lambda_Functions__ to enforce this constraint at compile-time (but not recommended because of extra boiler-plate code). ] -It is also possible to specify exceptions guarantees for destructors (see __Exception_Guarantees__, even if destructors should usually be programmed to not throw exceptions in C++ and in fact they are implicitly declared `noexcept` since C++11). +It is also possible to specify exceptions guarantees for destructors (see __Exception_Guarantees__, even if destructors should usually be programmed to not throw exceptions in C++, in fact destructors are implicitly declared `noexcept` since C++11). [footnote -Exceptions guarantees in destructors can access both the object `this` and its old value because the object exited before executing the destructor body and it still exists given the destructor body failed throwing an exception so the object should still be properly constructed and satisfy its class invariants. +Exceptions guarantees in destructors can access both the object `*this` and its old value because the object existed before executing the destructor body and it still exists given the destructor body failed throwing an exception so technically the object should still be properly constructed and satisfy its class invariants. ] The [funcref boost::contract::destructor] function takes `this` as a parameter (because destructors check class invariants, see __Class_Invariants__). The [funcref boost::contract::destructor] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::check] (otherwise this library will generate a run-time error, see [macroref BOOST_CONTRACT_ON_MISSING_CHECK_DECL]). Furthermore, C++11 `auto` declarations cannot be used here and the [classref boost::contract::check] type must be explicitly specified (otherwise this library will generate a compile-time error prior C++17 and a run-time error post C++17). -The destructor body is programmed right after the declaration of the RAII object. +The destructor body is programmed right after the declaration of this RAII object. At construction, the [classref boost::contract::check] RAII object for destructors does the following (enclosing destructor entry): @@ -539,6 +544,8 @@ 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]. ] +[heading Private and Protected Destructors] + 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: @@ -580,7 +587,7 @@ When called from non-static public functions, the [funcref boost::contract::publ 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 prior C++17 and a run-time error post C++17). -The public function body is programmed right after the declaration of the RAII object. +The public function body is programmed right after the declaration of this RAII object. At construction, the [classref boost::contract::check] RAII object for public functions does the following (enclosing public function entry): @@ -626,7 +633,7 @@ Programmers must pass the extra virtual parameter as the very first argument to [footnote *Rationale:* 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. +Furthermore, this parameter is internally used by this library to implement subcontracting (specifically to pass result and old values that are evaluated by the overriding function to the contracts of overridden virtual functions in base classes, and also to check preconditions, postconditions, and exception guarantees of overridden virtual functions in __OR__ and __AND__ with contracts of the overriding virtual function). ] 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__). @@ -653,7 +660,7 @@ For virtual public functions not returning `void`, programmers must also pass a 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 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. +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 to support subcontracting. ] class u { @@ -700,7 +707,7 @@ A virtual public function should always call [funcref boost::contract::public_fu [section Public Function Overrides (Subcontracting)] 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. +In this section, let's consider public functions (virtual or not) that override virtual public functions from one or more of their public base classes. For example (see [@../../example/features/public.cpp =public.cpp=]): [footnote In this documentation, function overrides are often marked with the code comment `/* override */`. @@ -711,13 +718,17 @@ On compilers that support C++11 virtual specifiers, the `override` identifier ca [public_function_override] [public_derived_class_end] -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__). +The extra `typedef` declared using [macroref BOOST_CONTRACT_BASE_TYPES] is required by this library for derived classes and it is internally used to detect base classes for subcontracting (see __Base_Classes__). +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. +] 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(func_name) + BOOST_CONTRACT_OVERRIDE(``[^['function-name]]``) -This can be declared at any point in the public section of the enclosing class (see __Access_Specifiers__ to use [macroref BOOST_CONTRACT_OVERRIDE] in a non-public section of the class instead). +This can be declared at any point in the public section of the enclosing class (see __Access_Specifiers__ to use [macroref BOOST_CONTRACT_OVERRIDE] also in a non-public section of the class). [macroref BOOST_CONTRACT_OVERRIDE] is used only once in a class for a given function name and overloaded functions can reuse the same [^override_['function-name]] definition (see __Function_Overloads__). [macroref BOOST_CONTRACT_NAMED_OVERRIDE] can be used to generate a name different than [^override_['function-name]] (e.g., to avoid generating C++ reserved names containing double underscores "`__`" for function names that already start with an underscore "`_`", see __Named_Overrides__). For convenience [macroref BOOST_CONTRACT_OVERRIDES] can be used with multiple function names instead of repeating [macroref BOOST_CONTRACT_OVERRIDE] for each function name (on compilers that support variadic macros). @@ -727,26 +738,21 @@ For example, for three functions named `f`, `g`, and `h` (but same for any other 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). +There is no equivalent of [macroref BOOST_CONTRACT_NAMED_OVERRIDE] that operates on multiple function names at once ([macroref BOOST_CONTRACT_NAMED_OVERRIDE] is not expected to be used often so it can simply be repeated multiple times when needed). ] BOOST_CONTRACT_OVERRIDE(f) BOOST_CONTRACT_OVERRIDE(g) BOOST_CONTRACT_OVERRIDE(h) -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). +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`, if 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_OLDOF] and [funcref boost::contract::public_function] calls in the public function override definition (see __Virtual_Public_Functions__). -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. +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 `std::bind`'s syntax. -The function pointer and references to all function arguments are needed for public function overrides because this library has to call overridden virtual public functions to check their contracts for subcontracting (even if this library will not actually execute the bodies of the overridden functions). +The function pointer and references to all function arguments are needed for public function overrides because this library has to internally 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`: @@ -763,7 +769,6 @@ For public function overrides returning `void`: ... } - BOOST_CONTRACT_OVERRIDE(f) ... @@ -775,7 +780,7 @@ For public function overrides not returning `void`, programmers must also pass a 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 has the function pointer so it will generate a compile-time error if the function is non-void and programmers forget to specify the extra return value parameter (this extra error checking is not possible instead for non-overriding virtual public functions because their contracts do not take the function pointer as a parameter, see __Virtual_Public_Functions__). ] -In this case, the library will pass this return value reference to the postcondition functor that must therefore take one single argument matching the return type, otherwise this library will generate a compile-time error (the functor parameter can be a constant reference `const&` to avoid extra copies of the return value): +In 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, similarly to non-overriding non-void __Virtual_Public_Functions__): class u { public: @@ -791,7 +796,6 @@ In this case, the library will pass this return value reference to the postcondi ... // Assign `result` at each return. } - BOOST_CONTRACT_OVERRIDE(f) ... @@ -800,7 +804,7 @@ In this case, the library will pass this return value reference to the postcondi 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:* -The `boost::bad_any_cast` exception could not used here because it does not print the from- and to- type names (so it is not descriptive enough). +The `boost::bad_any_cast` exception was not used here because it does not print the from- and to- type names (so it is not descriptive enough). ] [important @@ -808,7 +812,7 @@ It is the responsibility of the programmers to pass the extra virtual parameter 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). *Mnemonics:* -[:When `override_...` is present, always pass it as template parameter to [funcref boost::contract::public_functioon].] +[:When `override_...` is present, always pass it as template parameter to [funcref boost::contract::public_function].] [:When `v` is present, always pass it as the first argument to [funcref boost::contract::public_function] and [macroref BOOST_CONTRACT_OLDOF].] [:Always pass `result` to [funcref boost::contract::public_function] right after `v` for non-void functions.] ] @@ -826,7 +830,7 @@ 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 public function override contracts and subcontracts are correctly checked at run-time (see __Public_Function_Calls__). +This ensures that contracts and subcontracts of public function overrides are correctly checked at run-time in accordance with the __substitution_principle__ (see __Public_Function_Calls__). For the rest, considerations made in __Virtual_Public_Functions__ apply to public function overrides as well. @@ -844,8 +848,8 @@ For example (see [@../../example/features/base_types.cpp =base_types.cpp=]): [import ../example/features/base_types.cpp] [base_types] -For convenience, a local macro named `BASES` can be used to avoid repeating the base list twice (first in the derived class declaration `class `[^['class-name]]` : `[^['base-list]] and then again when invoking `BOOST_CONTRACT_BASE_TYPES(`[^['base-list]]`)`). -Being a local macro, `BASES` must be undefined using `#undef BASES` after it has been used to declare `base_types` (to avoid name clashes and macro redefinition errors). +For convenience, a /local macro/ named `BASES` can be used to avoid repeating the base list twice (first in the derived class declaration `class `[^['class-name]]` : `[^['base-list]] and then again when invoking `BOOST_CONTRACT_BASE_TYPES(`[^['base-list]]`)`). +Being a local macro, `BASES` must be undefined using `#undef BASES` after it is used to declare the `base_types` `typedef` (to avoid name clashes and macro redefinition errors). [footnote The name of this local macro is arbitrary, but `BASES` is often used in this documentation. ] @@ -859,9 +863,9 @@ This library will generate a compile-time error if the first base is missing its [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__). -[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. +[macroref BOOST_CONTRACT_BASE_TYPES] inspects each inheritance access level using preprocessor meta-programming and removes non-public bases from the list of bases internally used for subcontracting. However, this library cannot always detect when programmers forget to specify the inheritance access level because, when commas are used to separate template parameters passed to base classes, the preprocessor will not be able to correctly use commas to identify the next base class token in the inheritance list (the preprocessor cannot distinguish between commas that are not protected by round parenthesis, like the ones used in templates). -Therefore, this library relies on inheritance access levels to program the preprocessor to correctly identify the next base class token in the inheritance list (thus inheritance access levels must always be explicit specified by programmers). +Therefore, this library uses the inheritance access level keyword `public`, `protected`, or `private` instead of commas `,` for the preprocessor to correctly find the next base class token in the inheritance list (thus inheritance access levels must always be explicit specified by programmers for each base). ] 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). @@ -888,7 +892,7 @@ For example (see [@../../example/features/static_public.cpp =static_public.cpp=] [static_public] It is possible to specify preconditions, postconditions, and exception guarantees for static public functions (see __Preconditions__, __Postconditions__, and __Exception_Guarantees__). -When called from static public functions, [funcref boost::contract::public_function] cannot take the object `this` as a parameter (because there is no object `this` in static member functions) so the enclosing class type is is specified as an explicit template parameter (the class type is required to check static class invariants, see __Class_Invariants__): +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 specified via an explicit template parameter as in [funcref boost::contract::public_function][^<['class-type]>] (the class type is required to check static class invariants, see __Class_Invariants__): class u { public: @@ -908,7 +912,7 @@ When called from static public functions, [funcref boost::contract::public_funct 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 prior C++17 and a run-time error post C++17). -The static public functions body is programmed right after the declaration of the RAII object. +The static public functions body is programmed right after the declaration of this RAII object. At construction, the [classref boost::contract::check] RAII object for static public functions does the following (enclosing static public function entry): diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index bc09b0bf..3fe6e2fa 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -39,6 +39,8 @@ test-suite features : [ boost_contract_build.subdir-run features : volatile ] [ boost_contract_build.subdir-run-cxx11 features : old_if_copyable ] + [ boost_contract_build.subdir-run-cxx11 features : if_constexpr : + [ requires cxx17_if_constexpr ] ] [ boost_contract_build.subdir-run-cxx11 features : condition_if ] [ boost_contract_build.subdir-run-cxx11 features : call_if_cxx14 : [ requires cxx14_generic_lambdas ] ] diff --git a/example/features/access.cpp b/example/features/access.cpp index d32f298e..07586172 100644 --- a/example/features/access.cpp +++ b/example/features/access.cpp @@ -45,7 +45,7 @@ template class vector #define BASES public pushable : BASES -{ +{ // Private section of the class. friend class boost::contract::access; // Friend `access` class so... typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // ...private bases. @@ -57,7 +57,7 @@ class vector BOOST_CONTRACT_OVERRIDE(push_back) // ...private overrides. -public: +public: // Public section of the class. void push_back(T const& value, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_size = @@ -82,7 +82,7 @@ class vector unsigned max_size() const { return vect_.max_size(); } unsigned capacity() const { return vect_.capacity(); } -private: +private: // Another private section. std::vector vect_; }; diff --git a/example/features/check.cpp b/example/features/check.cpp index e82cb8cd..36aa9da3 100644 --- a/example/features/check.cpp +++ b/example/features/check.cpp @@ -30,7 +30,7 @@ int gcd(int const a, int const b) { //[check int main() { // Implementation checks (via nullary functor). - boost::contract::check c = [&] { + boost::contract::check c = [] { BOOST_CONTRACT_ASSERT(gcd(12, 28) == 4); BOOST_CONTRACT_ASSERT(gcd(4, 14) == 2); }; diff --git a/example/features/if_constexpr.cpp b/example/features/if_constexpr.cpp new file mode 100644 index 00000000..f4561f14 --- /dev/null +++ b/example/features/if_constexpr.cpp @@ -0,0 +1,113 @@ + +// Copyright (C) 2008-2019 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include +#include +#include +#include + +//[if_constexpr +template +void swap(T& x, T& y) { + constexpr bool b = boost::contract::is_old_value_copyable::value && + boost::has_equal_to::value; + boost::contract::old_ptr old_x, old_y; + if constexpr(b) { // Contract requires copyable T... + old_x = BOOST_CONTRACT_OLDOF(x); + old_y = BOOST_CONTRACT_OLDOF(y); + } + boost::contract::check c = boost::contract::function() + .postcondition([&] { + if constexpr(b) { // ... and T with `==`... + BOOST_CONTRACT_ASSERT(x == *old_y); + BOOST_CONTRACT_ASSERT(y == *old_x); + } + }) + ; + + T t = std::move(x); // ...but body only requires movable T. + x = std::move(y); + y = std::move(t); +} +//] + +struct i { // Non-copyable but has operator==. + explicit i(int n) : n_(n) {} + + i(i const&) = delete; // Non-copyable. + i& operator=(i const&) = delete; + + i(i const&& o) : n_(o.n_) {} + i& operator=(i const&& o) { n_ = o.n_; return *this; } + + friend bool operator==(i const& l, i const& r) { // Operator==. + return l.n_ == r.n_; + } + +private: + int n_; +}; + +struct j { // Copyable but no operator==. + explicit j(int n) : n_(n) {} + + j(j const& o) : n_(o.n_) {} // Copyable. + j& operator=(j const& o) { n_ = o.n_; return *this; } + + j(j const&& o) : n_(o.n_) {} + j& operator=(j const&& o) { n_ = o.n_; return *this; } + + // No operator==. + +private: + int n_; +}; + +struct k { // Non-copyable and no operator==. + explicit k(int n) : n_(n) {} + + k(k const&) = delete; // Non-copyable. + k& operator=(k const&) = delete; + + k(k const&& o) : n_(o.n_) {} + k& operator=(k const&& o) { n_ = o.n_; return *this; } + + // No operator==. + +private: + int n_; +}; + +int main() { + { // Copyable and operator== (so checks postconditions). + int x = 123, y = 456; + swap(x, y); + assert(x == 456); + assert(y == 123); + } + + { // Non-copyable (so does not check postconditions). + i x{123}, y{456}; + swap(x, y); + assert(x == i{456}); + assert(y == i{123}); + } + + { // No operator== (so does not check postconditions). + j x{123}, y{456}; + swap(x, y); + // Cannot assert x and y because no operator==. + } + + { // Non-copyable and no operator== (so does not check postconditions). + k x{123}, y{456}; + swap(x, y); + // Cannot assert x and y because no operator==. + } + + return 0; +} + diff --git a/example/features/lambda.cpp b/example/features/lambda.cpp index 4bbc0174..6eb99980 100644 --- a/example/features/lambda.cpp +++ b/example/features/lambda.cpp @@ -25,7 +25,7 @@ int main() { boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( - total + x <= std::numeric_limits::max()); + total < std::numeric_limits::max() - x); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(total == *old_total + x); diff --git a/example/features/loop.cpp b/example/features/loop.cpp index 1fa2dd90..1d8acdd7 100644 --- a/example/features/loop.cpp +++ b/example/features/loop.cpp @@ -23,7 +23,7 @@ int main() { boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( - total + *i <= std::numeric_limits::max()); + total < std::numeric_limits::max() - *i); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(total == *old_total + *i); diff --git a/example/features/old.cpp b/example/features/old.cpp index ec732a0c..bdf8b8c6 100644 --- a/example/features/old.cpp +++ b/example/features/old.cpp @@ -11,17 +11,17 @@ //[old char replace(std::string& s, unsigned index, char x) { char result; - boost::contract::old_ptr old_y; // Null, old value copied later... + boost::contract::old_ptr old_char; // 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]); + old_char = BOOST_CONTRACT_OLDOF(s[index]); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(s[index] == x); - BOOST_CONTRACT_ASSERT(result == *old_y); + BOOST_CONTRACT_ASSERT(result == *old_char); }) ; diff --git a/example/features/old_if_copyable.cpp b/example/features/old_if_copyable.cpp index 156400fc..8cf1acc7 100644 --- a/example/features/old_if_copyable.cpp +++ b/example/features/old_if_copyable.cpp @@ -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 here... */ } + w(w const&) { /* Some very expensive copy operation here... */ } /* ... */ //] diff --git a/example/features/public.cpp b/example/features/public.cpp index 7beb921f..a6d94aa7 100644 --- a/example/features/public.cpp +++ b/example/features/public.cpp @@ -24,7 +24,8 @@ class unique_identifiers : // Contract for a constructor. unique_identifiers(int from, int to) : boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(from <= to); + BOOST_CONTRACT_ASSERT(from >= 0); + BOOST_CONTRACT_ASSERT(to >= from); }) { boost::contract::check c = boost::contract::constructor(this) @@ -61,6 +62,9 @@ class unique_identifiers : bool find(int id) const { bool result; boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(id >= 0); + }) .postcondition([&] { if(size() == 0) BOOST_CONTRACT_ASSERT(!result); }) @@ -84,6 +88,7 @@ class unique_identifiers : boost::contract::check c = boost::contract::public_function( v, result, this) // Pass `v` and `result`. .precondition([&] { + BOOST_CONTRACT_ASSERT(id >= 0); BOOST_CONTRACT_ASSERT(!find(id)); // ID cannot be already present. }) .postcondition([&] (int const result) { @@ -132,9 +137,10 @@ class identifiers boost::contract::old_ptr old_size = BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function< - override_push_back // Pass override plus below function pointer... + override_push_back // Pass override type plus below function pointer... >(v, result, &identifiers::push_back, this, id) // ...and arguments. .precondition([&] { // Check in OR with bases. + BOOST_CONTRACT_ASSERT(id >= 0); BOOST_CONTRACT_ASSERT(find(id)); // ID can be already present. }) .postcondition([&] (int const result) { // Check in AND with bases. diff --git a/example/features/throw_on_failure.cpp b/example/features/throw_on_failure.cpp index d2e73906..4cff315f 100644 --- a/example/features/throw_on_failure.cpp +++ b/example/features/throw_on_failure.cpp @@ -101,7 +101,7 @@ int main() { } )))); boost::contract::set_except_failure( - [] (boost::contract::from where) { + [] (boost::contract::from) { // Already an active exception so shall not throw another... std::clog << "ignored exception guarantee failure" << std::endl; }