|
Boost : |
Subject: Re: [boost] [contract] Mixin Boost.Contract and Boost.STM
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-04-02 15:52:36
Hi,
On Sat, Mar 20, 2010 at 10:34 AM, Lorenzo Caminiti
<lorcaminiti_at_[hidden]> wrote:
> On Tue, Mar 16, 2010 at 6:54 PM, vicente.botet <vicente.botet_at_[hidden]> wrote:
>> I was wondering if instead of repeating the fuction signature and the class 'signature'
>> you could be able to provide a macro CONTRACT_FUNCTION2 that allows to just write
>> #define CONTRACT_CLASS (class) (myvector) (inherit)(pushable<T>)
>> CONTRACT_FUNCTION2(
>> ((public) (void) (push_back)( (const T&)(element) ))
>
> I have experimented with this a similar idea in the past. However, I
> concluded that copyable class type and inheritance both need to be
> specified at the function-contract level (not at the class-contract
> level) because:
I was able to implement the CONTRACT_CLASS() macro with an interface
similar to what Vicente suggested.
I think this was an important improvement because:
1) Programmers no longer need to repeat the class and base classes
types within CONTRACT_FUNCTION() for every function. The class and
base classes types are only specified once within CONTRACT_CLASS().
2) Perhaps more importantly, now the library is able to
_automatically_ inspect the base classes to see if a specific function
should subcontract or not. This way programmers of derived classes can
no longer "cheat" avoiding to subcontract by omitting (inherit) in
CONTRACT_FUNCTION() -- in fact, (inherit) is gone all together from
the library API.
The myvector example of the documentation
http://dbcpp.sourceforge.net/index.html#contract__.introduction.an_example
now becomes:
#include "pushable.hpp"
#include <contract.hpp>
#include <vector>
template<typename T>
class myvector: public pushable<T> {
CONTRACT_CLASS( (myvector) (pushable<T>) /***** Class and base
classes specified here and only once *****/
(invariant) ({ // For static class invariants use `(static)
(invariant) ({ ... })`.
CONTRACT_ASSERT( (size() == 0) == empty() );
}) )
public:
void push_back(const T& element)
CONTRACT_FUNCTION( /***** No class and no (inherit) here anymore *****/
(public) (void) (push_back)( (const T&)(element) )
(copyable) /***** Copyable qualifier for the object is moved at the
end of the function signature (same as cv-qualifier) *****/
(precondition)({
CONTRACT_ASSERT( size() < max_size() );
})
(postcondition)({
CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
})
(body)({
vector_.push_back(element);
}) )
typedef typename std::vector<T>::size_type size_type;
size_type size(void) const { return vector_.size(); }
size_type max_size(void) const { return vector_.max_size(); }
bool empty(void) const { return vector_.empty(); }
const T& back(void) const { return vector_.back(); }
private:
std::vector<T> vector_;
};
Note that the (copyable) object qualifier is still specified at
function scope because for the same class a function might need
CONTRACT_OLDOF(this) in its postconditions while another might not. I
have decided to specify the (copyable) object qualifier at the end of
the function signature so to follow a similar syntax as for the
cv-qualifier "(const)/(volatile)/(copyable) at the end of a member
function signature qualify the object as const/volatile/copyable
within that member function".
>From an implementation prospective:
1) CONTRACT_CLASS() defines typedefs for the class and base classes
types with predefined names so that CONTRACT_FUNCTION() knows how to
access them.
2) CONTRACT_FUNCTION() expands to code that uses uses SFINAE to
inspect the base class types looking for the struct which defines the
function contract (see the "[has_function]" email thread).
3) The function contract struct has a unique name for a given function
within a class plus it differentiates if a base function is virtual or
not.
This way the library can automatically subcontract x::f() from the
contract of y::f() only if y is a base of x, and y is virtual, and
y::f() has a contract.
Thanks a lot for the suggestion.
Lorenzo
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk