
Hello all, I would like you to vote between one of the two options below. Which option do you prefer? (-) OPTION 1 requires programmers to repeat the function signature tokens twice -- in the function declaration and in the CONTRACT_FUNCTION() macro. (+) However, OPTION 1 seems to make the code more readable -- users not familiar with Boost.Contract can "skip" the tokens in the CONTRACT_FUNCTION() signature-sequence and just read the usual C++ function declaration. OPTION 1: The function declaration is programmed using the usual C++ syntax just before the CONTRACT_FUNCTION() macro. template<typename T> class myvector { CONTRACT_INVARIANT( ({ ... }) ) public: void push_back(const T& element) // Usual C++ push_back() declaration. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) ) ... }; OPTION 2: The CONTRACT_FUNCTION() macro automatically programs also the function declaration. template<typename T> class myvector { CONTRACT_INVARIANT( ({ ... }) ) public: // No usual C++ push_back() declaration here. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) ) ... }; Thank you. Lorenzo

On Sat, Mar 20, 2010 at 6:54 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
OPTION 1: The function declaration is programmed using the usual C++ syntax just before the CONTRACT_FUNCTION() macro.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: void push_back(const T& element) // Usual C++ push_back() declaration. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
OPTION 2: The CONTRACT_FUNCTION() macro automatically programs also the function declaration.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: // No usual C++ push_back() declaration here. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
The OPTION 1 example looks nicer, simply because there's a separate, "classic" C++ declaration before that weird CONTRACT_FUNCTION macro. Someone completely ignorant of Boost.Contract might not want to take the trouble of learning everything, and the (void) (push_back)((const T&) (element) )declaration in OPTION 2 might be skipped because it's right after all those (class)(copyable) etc. etc. because it looks too similar to them (and someone scanning and skipping over CONTRACT_FUNCTION might skip over them). Sincerely, AmkG

Hello, I would like to renew the request for all of you to express an opinion between OPTION 1 and 2 below. I am NOT asking you to understand Boost.Contract. On the contrary, the less you know about Boost.Contract the more your input is valuable for me. Please just indicate which syntax between OPTION 1 and 2 you would like the most (or dislike the least ;) ) to see in your header files. On Sat, Mar 20, 2010 at 10:54 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
OPTION 1: The function declaration is programmed using the usual C++ syntax just before the CONTRACT_FUNCTION() macro.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: void push_back(const T& element) // Usual C++ push_back() declaration. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
OPTION 2: The CONTRACT_FUNCTION() macro automatically programs also the function declaration.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: // No usual C++ push_back() declaration here. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
Thanks a lot! Lorenzo

Lorenzo Caminiti wrote:
Hello,
I would like to renew the request for all of you to express an opinion between OPTION 1 and 2 below. I am NOT asking you to understand Boost.Contract. On the contrary, the less you know about Boost.Contract the more your input is valuable for me.
Please just indicate which syntax between OPTION 1 and 2 you would like the most (or dislike the least ;) ) to see in your header files.
On Sat, Mar 20, 2010 at 10:54 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
OPTION 1: The function declaration is programmed using the usual C++ syntax just before the CONTRACT_FUNCTION() macro.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: void push_back(const T& element) // Usual C++ push_back() declaration. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
OPTION 2: The CONTRACT_FUNCTION() macro automatically programs also the function declaration.
template<typename T> class myvector {
CONTRACT_INVARIANT( ({ ... }) )
public: // No usual C++ push_back() declaration here. CONTRACT_FUNCTION( (class) (copyable)(myvector) (public) (void) (push_back)( (const T&)(element) ) (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )
... };
Thanks a lot! Lorenzo
Well, knowing very little about Boost.Contract except what I glean from the mailing list messages, I'd prefer OPTION 2, but with some minor tweaks. E.g., can the public/private/protected specification just be whatever the access is as the point of the macro invocation? I'd also prefer "(( const T&, element ))" to "( const T& ) ( element )", and perhaps a usage recommendation would be to #define the "( class ) ( copyable ) ( myvector )" to some preprocessor symbol so that you don't have to type it out for every CONTRACT_FUNCTION invocation. Perhaps you can have a variant of CONTRACT_FUNCTION that just uses some predefined macro to get the information encapsulated in "( class ) ( copyable ) ( myvector )" ? This might alleviate the parentheses problem, e.g., OTHER_CONTRACT_FUNCTION( public, void, push_back, (( const T&, element )) ) Also, are there going to be more design decision queries sent to the mailing list where "less knowledge is better"? If so, I will do my damnedest to remain ignorant ;) - Jeff

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

----- Original Message ----- From: "Lorenzo Caminiti" <lorcaminiti@gmail.com> To: <boost@lists.boost.org> Sent: Tuesday, April 06, 2010 3:59 PM Subject: Re: [boost] [contract] Macro syntax?
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.
Yes, this could be an option. <snip>
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.
Right.
(-) 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.
Yes, but the other option is not too readable neither.
(-) 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.*
This is a major drawback.
(~) 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.
Yes this could improbe the error reporting a little bit. Lorenzo, As the () syntax is quite ugly, I was wondering if adding a contract preprocessing phase CP_PP could be a option to consider. Each contract programming line could be prefixed by a comment such as //~//. template<typename T> class myvector: public pushable<T> { //~// invariant { //~// (size() == 0) == empty(); //~// } public: void push_back(const T& element) //~// precondition { //~// size() < max_size(); //~// } //~// postcondition { //~// size() == oldof(this)->size() + 1; //~// } { vector_.push_back(element); } .... private: std::vector<T> vector_; }; As any CP sentence is commented with a C++ comment this code could work without CP preprocessing. The CP_PP could generate #line directives so the original lines are preserved when warning or errors message are reported by the compiler. The generated file could be generated in a specific contract directory so these files can be sees by the compiler before the original ones. The user will just need to add -Icontract directives. Best, Vicente

On Tue, Apr 6, 2010 at 2:12 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Lorenzo, As the () syntax is quite ugly, I was wondering if adding a contract preprocessing phase CP_PP could be a option to consider. Each contract programming line could be prefixed by a comment such as //~//.
template<typename T> class myvector: public pushable<T> { //~// invariant { //~// (size() == 0) == empty(); //~// }
public: void push_back(const T& element) //~// precondition { //~// size() < max_size(); //~// } //~// postcondition { //~// size() == oldof(this)->size() + 1; //~// } { vector_.push_back(element); } .... private: std::vector<T> vector_; };
As any CP sentence is commented with a C++ comment this code could work without CP preprocessing.
The CP_PP could generate #line directives so the original lines are preserved when warning or errors message are reported by the compiler.
The generated file could be generated in a specific contract directory so these files can be sees by the compiler before the original ones. The user will just need to add -Icontract directives.
JContract uses Javadoc comments. Doxygen provides \pre, \post, and \invariant tags so if a preprocessor was to extract contracts from code comments it might make sense to use these tags... There is already a preprocessing-based CP tool for C++ called "C^2" but I _think_ is not maintained anymore. If I have some free time (but not likely in the short term), I would like look into what can be done to generate Boost.Contract code using Boost.Wave/Spirit. However, while I recognize the ugliness of the contract macros syntax, my goal and interest were and remain to see how CP can be implemented within the C++ language itself (without external preprocessing)... Thanks, Lorenzo

----- Original Message ----- From: "Lorenzo Caminiti" <lorcaminiti@gmail.com> To: <boost@lists.boost.org> Sent: Thursday, April 08, 2010 2:19 AM Subject: Re: [boost] [contract] Macro syntax? JContract uses Javadoc comments. Doxygen provides \pre, \post, and \invariant tags so if a preprocessor was to extract contracts from code comments it might make sense to use these tags... There is already a preprocessing-based CP tool for C++ called "C^2" but I _think_ is not maintained anymore. If I have some free time (but not likely in the short term), I would like look into what can be done to generate Boost.Contract code using Boost.Wave/Spirit. However, while I recognize the ugliness of the contract macros syntax, my goal and interest were and remain to see how CP can be implemented within the C++ language itself (without external preprocessing)... Thanks, Lorenzo _______________________________________________ I understand your concern Lorenzo. Having CP implemented within C++ is a good goal, and I expect that you would continue polishing it. If a preprocessing will be done I would expect however it follows the CP proposal as close as possible. This will allows to check this proposal before it can be accepted. I don't know which option will be the best, but I think that you need something that allows to analyze something more that the CP commented sentences. Maybe a C++ front-end could be used (LLVM?) Best, Vicente
participants (4)
-
Alan Manuel Gloria
-
Jeffrey Hellrung
-
Lorenzo Caminiti
-
vicente.botet