On 6/15/2016 11:30 AM, Lorenzo Caminiti wrote:
Hello all,
In the last few years my professional and personal lives changed quite a bit limiting my ability to contribute to Boost. However, in my spare time I slowing continued to revise Boost.Contract hoping to be able to commit it to a Boost release someday (after the library was accepted 3+ years ago... https://groups.google.com/forum/?fromgroups=#!topic/boost-list/jQ7OjAmos_Y). While doing so I realized that leveraging C++11 lambda functions, Boost.Contract could be re-implemented without its crazy macros that alter C++ function declaration syntax.
Boost.Contract still remains the only C++ library that implements *all* features of Contract Programming (a.k.a., Design by Contract or DbC): subcontracting, class invariants (also static and volatile), postconditions (with old and return values), preconditions, customizable actions on assertion failure (terminate, throw, etc.), optional assertion compilation, disable assertion checking while already checking other assertions (to avoid infinite recursion), etc. Furthermore, in its new incarnation Boost.Contract no longer uses crazy macros so it is easier to use, faster to compile, and gives readable compiler errors.
For example:
#include
int inc(int& x) { int result; boost::contract::old_ptr<int> old_x = BOOST_CONTRACT_OLDOF(x); boost::contract::guard c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(x < std::numeric_limits<int>::max()); }) .postcondition([&] { BOOST_CONTRACT_ASSERT(x == *old_x + 1); BOOST_CONTRACT_ASSERT(result == *old_x); }) ;
return result = x++; // Function body. }
Or with subcontracting:
#include
#include <vector> template<typename T> class pushable; // Arbitrary base to demo subcontracting.
template<typename T> class vector #define BASES public pushable<T> : BASES { public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. #undef BASES
void invariant() const { // Checked in AND with base class invariants. BOOST_CONTRACT_ASSERT(size() <= capacity()); // Line 25. }
virtual void push_back(T const& value, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr<unsigned> old_size = BOOST_CONTRACT_OLDOF(v, size()); // Old values. boost::contract::guard c = boost::contract::public_function< override_push_back>(v, &vector::push_back, this, value) .precondition([&] { // Checked in OR with base preconditions. BOOST_CONTRACT_ASSERT(size() < max_size()); // Line 35. }) .postcondition([&] { // Checked in AND with base postconditions. BOOST_CONTRACT_ASSERT(size() == *old_size + 1); // Line 38. }) ;
vect_.push_back(value); // Function body. } BOOST_CONTRACT_OVERRIDE(push_back) // For `override_push_back`.
// Could program contracts for those as well. unsigned size() const { return vect_.size(); } unsigned max_size() const { return vect_.max_size(); } unsigned capacity() const { return vect_.capacity(); }
private: std::vector<T> vect_; };
Full documentation and examples at: https://lcaminiti.github.io/boost-contract
What do you think?
Thanks, --Lorenzo
P.S. The library can also be used without C++11 lambda functions (or any C++11 specific feature) but programmers have to write a fare amount of extra code to program the precondition and postcondition functors (using non-local functions, Boost.LocalFunction, Boost.Funsion, Boost.Lambda, or some other approach) so that might not useful in practice.
You are certainly allowed to have your library require C++11. Since your library has already been accepted into Boost why not add it officially to Boost as a C++11 on up library ?