
On Sun, Mar 21, 2010 at 4:06 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
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.
What do you think if I provide both family of macros? 1) CONTRACT_CLASS() and CONTRACT_FUNCTION() which follow the relative class and function declarations as coded by the programmers. 2) CONTRACT_CLASS_DECL() and CONTRACT_FUNCTION_DECL() which also automatically program the class and function declarations so programmers do not have to code the declarations manually outside the contracts. 1) And example of CONTRACT_XYZ(): template<typename T> class myvector: public pushable<T> { CONTRACT_CLASS( (myvector) (public)(pushable<T>) (invariant) ({ CONTRACT_ASSERT( (size() == 0) == empty() ); }) ) public: void push_back(const T& element) CONTRACT_FUNCTION( (public) (void) (push_back)( (const T&)(element) ) (copyable) (precondition) ({ CONTRACT_ASSERT( size() < max_size() ); }) (postcondition) ({ CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); }) (body) ({ vector_.push_back(element); }) ) .... private: std::vector<T> vector_; }; 2) The same example with CONTRACT_XYZ_DECL(): template<typename T> CONTRACT_CLASS_DECL( (myvector) (public)(pushable<T>) (invariant) ({ CONTRACT_ASSERT( (size() == 0) == empty() ); }) ( // No class `{};` parenthesis. CONTRACT_FUNCTION_DECL( (public) (void) (push_back)( (const T&)(element) ) (copyable) (precondition) ({ CONTRACT_ASSERT( size() < max_size() ); }) (postcondition) ({ CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); }) (body) ({ vector_.push_back(element); }) ) ... private: std::vector<T> vector_; ) ) The CONTRACT_XYZ_DECL() macros have the following pro (+), cons (-), and neutrals (~) compared to the CONTRACT_XYZ() macros: (+) There is no code duplication when using CONTRACT_XYZ_DECL() (because the signature tokens only appear within the macro and not also before the macro). (+) When using CONTRACT_XYZ_DECL(), the declarations tokens will always match the ones in the contract because they are not duplicated. When using the CONTRACT_XYZ() macros instead, a mismatch between the declaration and the contract signature tokens will generate a compiler error in most, but not all, cases. (-) The code using CONTRACT_XYZ_DECL() is more difficult to read to whom does not know the library syntax because all usual C++ syntax is gone. (-) All compiler errors for the class will appear with the same line number because the CONTRACT_CLASS_DECL() macro will expand the entire class definition on a single line. I think this is a major defect of the CONTRACT_XYZ_DECL() macros because it will make C++ compiler error even harder to track than they currently are.* (~) The CONTRACT_XYZ_DECL() macros will need to accept additional information like inheritance access level, default parameter values, exception specifications, etc. However, the CONTRACT_XYZ() macros already contain most of the syntactic tokens of class and function declarations so this is not much of a complication of the macro signature syntax. (*) This issue can be avoided by mixing the use of CONTRACT_CLASS() with CONTRACT_FUNCTION_DECL() and separating the function definition from its declaration. This way both the class and function definition code will not be wrapped by any of the CONTRACT macros and the compiler error line numbers will retain their usual meaning. Lorenzo