[contract] Released Contract Programming Library on SourceForge

Hi all, I have released on SourceForge a library that implements Contract Programming (a.k.a. Design by Contract(TM) ) for C++. I am considering to submit this library to Boost (as Boost.Contract). Contract++ Library * Download http://sourceforge.net/projects/dbcpp/ * Documentation http://dbcpp.sourceforge.net/ * Examples http://dbcpp.sourceforge.net/contract__/examples.html Comments? Regards, Lorenzo

Hello all, On Fri, Feb 26, 2010 at 9:26 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
I have released on SourceForge a library that implements Contract Programming (a.k.a. Design by Contract(TM) ) for C++. I am considering to submit this library to Boost (as Boost.Contract).
Contract++ Library * Download http://sourceforge.net/projects/dbcpp/ * Documentation http://dbcpp.sourceforge.net/ * Examples http://dbcpp.sourceforge.net/contract__/examples.html
Comments?
I have also uploaded the Contract++ library files on the Boost Vault under "Correctness - Testing / Contract". Plus this is a list of the library known open issues http://dbcpp.sourceforge.net/contract__/todo.html Regards, Lorenzo

Hi, ----- Original Message ----- From: "Lorenzo Caminiti" <lorcaminiti@gmail.com> To: <boost@lists.boost.org> Sent: Friday, February 26, 2010 3:26 PM Subject: [boost] [contract] Released Contract Programming Library onSourceForge
Hi all,
I have released on SourceForge a library that implements Contract Programming (a.k.a. Design by Contract(TM) ) for C++. I am considering to submit this library to Boost (as Boost.Contract).
Contract++ Library * Download http://sourceforge.net/projects/dbcpp/ * Documentation http://dbcpp.sourceforge.net/ * Examples http://dbcpp.sourceforge.net/contract__/examples.html
Comments?
I wanted to tell you that I wanted to mix Boost.Contract with Boost.STM. Software Transactional Memory needs already to backup the data that is modified, so it can be rolled back on abort. Thus we can use this backup to get the value of the Old values. As the copy is done always, we don't need any more to specify that we need to copy to be able to get the Old values as in void push_back(const T& element) CONTRACT_FUNCTION( (class) (copyable)(myvector) (inherit)(pushable<T>) (public) (void) (push_back)( (const T&)(element) ) (precondition) ({ CONTRACT_ASSERT( size() < max_size() ); }) (postcondition) ({ CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); }) (body) ({ vector_.push_back(element); }) ) BTW, does it means that CP can not be applied to non CopyConstructible classes? In addition Boost.STM works also for classes that are not CopyConstructible, but that follows the Shallow Copy semantics. This will allow to test for Old values on these kind of classes. I have two questions. What (copyable) does on the constructor? Why it is not used on the destructor? I know that this will take long time, but I'm sure that the integration will be fruitful. I was wondering if instead of repeating the fuction signature and the class 'signature' void push_back(const T& element) CONTRACT_FUNCTION( (class) (copyable)(myvector) (inherit)(pushable<T>) (public) (void) (push_back)( (const T&)(element) ) 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) )) (precondition)({ CONTRACT_ASSERT( size() < max_size() ); ... // More preconditions. }) (postcondition)({ CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); ... // More postconditions. }) (body)({ vector_.push_back(element); // Original implementation. }) ) ... // Rest of the class. #undef CONTRACT_CLASS CONTRACT_FUNCTION2 will just use the CONTRACT_CLASS macro to get the class 'signature'. Note that the first argument of CONTRACT_FUNCTION2 contain itself a PP sequence. CONTRACT_FUNCTION2( (signature-sequence) precondition-sequence postcondition-sequence body-sequence ) == REMOVE_PARENTHESIS(signature-sequence) CONTRACT_FUNCTION( ( CONTRACT_CLASS signature-sequence) precondition-sequence postcondition-sequence body-sequence ) Best, Vicente

Hello: On Tue, Mar 16, 2010 at 6:54 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
I wanted to tell you that I wanted to mix Boost.Contract with Boost.STM. Software Transactional Memory needs already to
OK, once you start looking into it, please let me know. I will be happy to help. I am not familiar with Boost.STM so I will take a look at it in the meanwhile.
As the copy is done always, we don't need any more to specify that we need to copy to be able to get the Old values as in
Note that in Boost.Contract not only the object but also the function arguments can be tagged copyable. For example, if myvector was to have a swap_back() operation, which swapped the vector's back with the specified element, the contract could be written as follow: void swap_back(T& element) CONTRACT_FUNCTION( (class) (copyable)(myvector) // Copy object. (public) (void) (swap_back)( (copyable)(T&)(element) ) // Copy argument. (postcondition) ({ CONTRACT_ASSERT( back() == CONTRACT_OLDOF(element) ); CONTRACT_ASSERT( element == CONTRACT_OLDOF(this)->back() ); }) (body) ( ... ) ) Would Boost.STM allow to copy also the function arguments?
BTW, does it means that CP can not be applied to non CopyConstructible classes?
Yes, doing the copies all the times would have the following plus and minus: (+) The signature-sequence syntax will be simpler without the user needing to specify (copyable) explicitly. (-) Contracts can ONLY be written for objects and argument types that can be copied -- even if the specific function contract does not use OLDOF()... (-) The run-time overhead of the copy operation will ALWAYS be present -- even if the specific function contract does not use OLDOF()... I think the last two minus would be major limitations for Boost.Contract... hopefully, there is a way to use Boost.STM without imposing these 2 key limitations on Boost.Contract...
In addition Boost.STM works also for classes that are not CopyConstructible, but that follows the Shallow Copy semantics. This will allow to test for Old values on these kind of classes.
Boost.Contract now implements one of your previous suggestions to relax the ConstCopyConstructible requirement. Boost.Contract copies a type T via the following contract::copy: namespace contract { template<typename T> class copy: boost::noncopyable { private: typedef typename boost::add_const<typename boost::remove_reference<T>::type>::type const_type; typedef typename boost::add_reference<const_type>::type const_ref; public: const_type value; copy(const_ref source): value(source) {} // Use T's constant copy constructor. }; } By default, this uses T's (public) constant copy constructor to make the copy. However, programmers can specialize contract::copy for a given type so to relax the ConstCopyConstructible requirement for that type. For example http://dbcpp.sourceforge.net/example/Mitchell2002/counter/decrement_button.h... allows to copy a type which is boost::noncopyable plus performs a deep copy (instead of a shallow copy) of a member reference. Vicente: I think this is inline with what you suggested me a few months back. BTW, thanks a lot for the idea, it worked out quite nicely!
I have two questions. What (copyable) does on the constructor? Why it is not used on the destructor?
Constructors (copyable) cannot be applied to the object for constructors (Boost.Contract will generate a compile-time error otherwise). This is because there is no object before body execution so "copy the object before the body" does not make sense. Constructor arguments can still be copied instead. Destructor (copyable) cannot be applied to the object for destructor (Boost.Contract will generate a compile-time error otherwise). This is because the destructor has no postconditions -- there are no postconditions because there are no arguments and there is no object after destructor body execution (the object has been destructed).
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: 1. Each function should be allowed to tag the class copyable because one function might use OLDOF() in its postconditions while another function might not. The need for programmer to specify (copyable) could be removed but only if I could metaprogram something like this "if CONTRACT_OLDOF(variable-name) appears in this function postcondition then replace variable-type with contract::copyable<variable-type>..." -- I was not able to metaprogram something like that nor with the Boost.Preprocessor, nor with Boost.MPL. 2. (inherit) also needs to be specified at the function level because a specific function c::f() might override x::f() and y::f(), but c::g() overrides z::g(), and maybe c::h() does not override -- where x, y, and z are base classes of c. For a given function, the compiler knows if that same function appears in one of the base classes but the library does not. Therefore for a given function the programmers must indicate the specific subset of base classes from which that function is inherited from (and the library will subcontract from these specific base functions). Again, this could be avoided if I could metaprogram "for c::f(), if x::f() exists (true) do something; or z::f() exists (false) do something; ..." -- I was not able to metaprogram this. One way I have investigated to omit the class type from signature-sequence is to move it into the invariant: template<typename T> class myvector { CONTRACT_INVARIANT( (copyable)(myvector) ({ // Class type is here. ... // Invariants. }) ) public: void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) ) ... ) size_t size(void) const CONTRACT_FUNCTION( // No class type and no inherit here. (public) (void) (push_back)( (const T&)(element) ) ... ) }; Which could expand to something like this: template<typename T> class myvector { typedef contract::copyable<myvector> contract_class_type_; // Expanded from INVARIANT(). ... // The usual invariant check code. public: void push_back(const T& element) ... // The function contract check code now using contract_class_type_ for the class type. }; Note: 1) There is no inherit for size() so (inherit) cannot be moved into the invariant. 2) Now CONTRACT_FUNCTION() expansion will use contract_class_type_ for the class type. But again, by doing so either all functions copy the object or they do not regardless of whether a function actually uses OLDOF(this) in its postcondition (and adding useless run-time overhead for the unused OLDOF(this) copies). Therefore I decided not to move the class type into the invariant so to allow each function to selectively tag it (copyable) only in case they need and use the object old value. Regards, Lorenzo

Hi, ----- Original Message ----- From: "Lorenzo Caminiti" <lorcaminiti@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, March 20, 2010 3:34 PM Subject: Re: [boost] [contract] Mixin Boost.Contract and Boost.STM Hello: On Tue, Mar 16, 2010 at 6:54 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
I wanted to tell you that I wanted to mix Boost.Contract with Boost.STM. Software Transactional Memory needs already to
OK, once you start looking into it, please let me know. I will be happy to help. I am not familiar with Boost.STM so I will take a look at it in the meanwhile.
As the copy is done always, we don't need any more to specify that we need to copy to be able to get the Old values as in
Note that in Boost.Contract not only the object but also the function arguments can be tagged copyable. For example, if myvector was to have a swap_back() operation, which swapped the vector's back with the specified element, the contract could be written as follow: void swap_back(T& element) CONTRACT_FUNCTION( (class) (copyable)(myvector) // Copy object. (public) (void) (swap_back)( (copyable)(T&)(element) ) // Copy argument. (postcondition) ({ CONTRACT_ASSERT( back() == CONTRACT_OLDOF(element) ); CONTRACT_ASSERT( element == CONTRACT_OLDOF(this)->back() ); }) (body) ( ... ) ) Would Boost.STM allow to copy also the function arguments? VBE> Unfortunately, only the transactional objects are backed up. So if the parameters are not transactional they will be not be backed up :(.
BTW, does it means that CP can not be applied to non CopyConstructible classes?
Yes, doing the copies all the times would have the following plus and minus: (+) The signature-sequence syntax will be simpler without the user needing to specify (copyable) explicitly. (-) Contracts can ONLY be written for objects and argument types that can be copied -- even if the specific function contract does not use OLDOF()... (-) The run-time overhead of the copy operation will ALWAYS be present -- even if the specific function contract does not use OLDOF()... I think the last two minus would be major limitations for Boost.Contract... hopefully, there is a way to use Boost.STM without imposing these 2 key limitations on Boost.Contract... VBE> We can conclude that Boost.STM could leverage the two minus points for transactional objects. For non transactional objects the (-) will be yet present.
In addition Boost.STM works also for classes that are not CopyConstructible, but that follows the Shallow Copy semantics. This will allow to test for Old values on these kind of classes.
Boost.Contract now implements one of your previous suggestions to relax the ConstCopyConstructible requirement. Boost.Contract copies a type T via the following contract::copy: namespace contract { template<typename T> class copy: boost::noncopyable { private: typedef typename boost::add_const<typename boost::remove_reference<T>::type>::type const_type; typedef typename boost::add_reference<const_type>::type const_ref; public: const_type value; copy(const_ref source): value(source) {} // Use T's constant copy constructor. }; } VBE> Great. This is very important as not all the classes are copy constructible. By default, this uses T's (public) constant copy constructor to make the copy. However, programmers can specialize contract::copy for a given type so to relax the ConstCopyConstructible requirement for that type. For example http://dbcpp.sourceforge.net/example/Mitchell2002/counter/decrement_button.h... allows to copy a type which is boost::noncopyable plus performs a deep copy (instead of a shallow copy) of a member reference. Vicente: I think this is inline with what you suggested me a few months back. BTW, thanks a lot for the idea, it worked out quite nicely! VBE> Yes, this is exactly what I was looking for.
I have two questions. What (copyable) does on the constructor? Why it is not used on the destructor?
Constructors (copyable) cannot be applied to the object for constructors (Boost.Contract will generate a compile-time error otherwise). This is because there is no object before body execution so "copy the object before the body" does not make sense. Constructor arguments can still be copied instead. Destructor (copyable) cannot be applied to the object for destructor (Boost.Contract will generate a compile-time error otherwise). This is because the destructor has no postconditions -- there are no postconditions because there are no arguments and there is no object after destructor body execution (the object has been destructed). VBE> I think you need to update the docs then (see the grammar part)
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: 1. Each function should be allowed to tag the class copyable because one function might use OLDOF() in its postconditions while another function might not. The need for programmer to specify (copyable) could be removed but only if I could metaprogram something like this "if CONTRACT_OLDOF(variable-name) appears in this function postcondition then replace variable-type with contract::copyable<variable-type>..." -- I was not able to metaprogram something like that nor with the Boost.Preprocessor, nor with Boost.MPL. VBE> Maybe you can provide two family of macros, one using a copyable class and the other no (maybe associated to const/non const functions). These macros will use the CONTRACT_CLASS and behave as now. 2. (inherit) also needs to be specified at the function level because a specific function c::f() might override x::f() and y::f(), but c::g() overrides z::g(), and maybe c::h() does not override -- where x, y, and z are base classes of c. For a given function, the compiler knows if that same function appears in one of the base classes but the library does not. Therefore for a given function the programmers must indicate the specific subset of base classes from which that function is inherited from (and the library will subcontract from these specific base functions). Again, this could be avoided if I could metaprogram "for c::f(), if x::f() exists (true) do something; or z::f() exists (false) do something; ..." -- I was not able to metaprogram this. VBE> If I understand, you mean that if a class inherits from x,y,z, you dont need to specific the (inherit) for all the classes but only the class the function is been overriding, isn't it? One way I have investigated to omit the class type from signature-sequence is to move it into the invariant: template<typename T> class myvector { CONTRACT_INVARIANT( (copyable)(myvector) ({ // Class type is here. ... // Invariants. }) ) public: void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) ) ... ) size_t size(void) const CONTRACT_FUNCTION( // No class type and no inherit here. (public) (void) (push_back)( (const T&)(element) ) ... ) }; Which could expand to something like this: template<typename T> class myvector { typedef contract::copyable<myvector> contract_class_type_; // Expanded from INVARIANT(). ... // The usual invariant check code. public: void push_back(const T& element) ... // The function contract check code now using contract_class_type_ for the class type. }; Note: 1) There is no inherit for size() so (inherit) cannot be moved into the invariant. 2) Now CONTRACT_FUNCTION() expansion will use contract_class_type_ for the class type. But again, by doing so either all functions copy the object or they do not regardless of whether a function actually uses OLDOF(this) in its postcondition (and adding useless run-time overhead for the unused OLDOF(this) copies). Therefore I decided not to move the class type into the invariant so to allow each function to selectively tag it (copyable) only in case they need and use the object old value. VBE> I see. You have no comented my suggestion to don't duplicate the signature. Instead of letting the C++ signature, generate it from the macro, so void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) ) will become // NO NEED OF THE C++ SIGNATURE // void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) ) As Boost.STM will not solve completly the (-) issues, I'm less motivated to see how the integration works. I will add to my TO BE ANALIZED list. Hoping my suggestions could help you. Best, Vicente

Hello: On Sat, Mar 20, 2010 at 11:53 AM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
2. (inherit) also needs to be specified at the function level because a specific function c::f() might override x::f() and y::f(), but c::g() overrides z::g(), and maybe c::h() does not override -- where x, y, and z are base classes of c. For a given function, the compiler knows if that same function appears in one of the base classes but the library does not. Therefore for a given function the programmers must indicate the specific subset of base classes from which that function is inherited from (and the library will subcontract from these specific base functions). Again, this could be avoided if I could metaprogram "for c::f(), if x::f() exists (true) do something; or z::f() exists (false) do something; ..." -- I was not able to metaprogram this.
VBE> If I understand, you mean that if a class inherits from x,y,z, you dont need to specific the (inherit) for all the classes but only the class the function is been overriding, isn't it?
Sorry, I was not able to explain myself. I will try to clarify. Boost.Contract is not capable to automatically subcontract. If inherit is not specified, there is no subcontracting and the library does not give any error (this is NOT ideal... it's a limitation of the library). The reason for this is that the library does not automatically know if a given function c::f() is overriding one (or more) base functions or not. The C++ compiler knowns because it can inspect all base classes x, y, z, ... looking for x::f(), y::f(), ... but I was not able to metaprogram this automatic "base class inspection" in the library. For example, let: struct x { virtual void f() CONTRACT_FUNCTION( ... ) ... }; struct y { virtual void f() CONTRACT_FUNCTION( ... ) ... }; struct z { // No void f() here. ... }; Then: struct c: x, y, z { // (1) void f() CONTRACT_FUNCTION( (struct) (c) (inherit)(x) (inherit)(y) ... ) // Compiles and subcontracts. }; struct c: x, y, z { // (2) void f() CONTRACT_FUNCTION( (struct) (c) ... ) // Doesn't subcontract but still compiles... }; struct c: x, y, z { // (3) void f() CONTRACT_FUNCTION( (struct) (c) (inherit)(x) ... ) // Only subcontract from x but still compiles... }; struct c: x, y, z { // (4) void f() CONTRACT_FUNCTION( (struct) (c) (inherit)(z) ... ) // Does not compile because z::f() does not exist. }; (2) and (3) are limitations of the library -- they should not compile because the programmers of the derived class are avoiding to subcontract. (1) is also a "limitation" because ideally the library would automatically know when to subcontract without the need for programmers to specify (inherit) at all. (4) is fine. I was not able to overcome these limitations because I could not metaprogram code that "inspects" the base classes looking for the existence of a `virtual f()`... Is this possible? (E.g., I do not know how boost::is_base_of works and, who knows, maybe that technique is relevant to overcome these Boost.Contract limitations...)
You have no comented my suggestion to don't duplicate the signature. Instead of letting the C++ signature, generate it from the macro, so
This is possible (I will have to extend the signature-sequence just a bit to include default argument values, exception specifications, member list initializations, and absolutely anything else you can program in a C++ function declaration -- but most of the declaration tokens are already there). There is a question of what syntax is more readable vs. which syntax requires more programmers' coding work. I have asked this question to all Boosters -- see separate email thread.
As Boost.STM will not solve completly the (-) issues, I'm less motivated to see how the integration works. I will add to my TO BE ANALIZED list.
I understand. Regards, Lorenzo

----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Saturday, March 20, 2010 4:53 PM Subject: Re: [boost] [contract] Mixin Boost.Contract and Boost.STM
You have no comented my suggestion to don't duplicate the signature. Instead of letting the C++ signature, generate it from the macro, so
void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
will become
// NO NEED OF THE C++ SIGNATURE // void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
Hi, please could you comment my suggestion? Best, Vicente

Hi Vicente,
You have no comented my suggestion to don't duplicate the signature. Instead of letting the C++ signature, generate it from the macro, so
void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
will become
// NO NEED OF THE C++ SIGNATURE // void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
Hi, please could you comment my suggestion?
This is possible (I will have to extend the signature-sequence just a bit to include default argument values, exception specifications, member list initializations, and absolutely anything else you can program in a C++ function declaration -- but most of the declaration tokens are already there). There is a question of what syntax is more readable vs. which syntax requires more programmers' coding work. I have asked this question to all Boosters -- see separate email thread. Thanks, Lorenzo

----- Original Message ----- From: "Lorenzo Caminiti" <lorcaminiti@gmail.com> To: <boost@lists.boost.org> Sent: Sunday, March 21, 2010 6:01 PM Subject: Re: [boost] [contract] Mixin Boost.Contract and Boost.STM Hi Vicente,
You have no comented my suggestion to don't duplicate the signature. Instead of letting the C++ signature, generate it from the macro, so
void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
will become
// NO NEED OF THE C++ SIGNATURE // void push_back(const T& element) CONTRACT_FUNCTION( (inherit)(pushable<T>) // No class type. (public) (void) (push_back)( (const T&)(element) )
Hi, please could you comment my suggestion?
This is possible (I will have to extend the signature-sequence just a bit to include default argument values, exception specifications, member list initializations, and absolutely anything else you can program in a C++ function declaration -- but most of the declaration tokens are already there). There is a question of what syntax is more readable vs. which syntax requires more programmers' coding work. I have asked this question to all Boosters -- see separate email thread. Thanks, Lorenzo _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost I see the probelems this could introduce. I think howver thatn we should try to provide interfaces that don't impose the user to repeat redundant information. Vicente

Hi, On Sat, Mar 20, 2010 at 10:34 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote: > On Tue, Mar 16, 2010 at 6:54 PM, vicente.botet <vicente.botet@wanadoo.fr> 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
participants (2)
-
Lorenzo Caminiti
-
vicente.botet