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.