|
Boost : |
Subject: Re: [boost] [contract] Without the macros
From: Edward Diener (eldiener_at_[hidden])
Date: 2016-06-15 12:03:24
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 <boost/contract.hpp>
>
> 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 <boost/contract.hpp>
> #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 ?
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk