Re: [boost] [contract] syntax redesign

Comments are always welcome :)
Hi Lorenzo, The number of examples is impressive. It is a pleasure to observe your library growing at this pace. I would like to suggest two things. I could not see from the examples, if the library is capable of supporting "function try blocks" in constructor and destructor definitions. This is what I mean. http://msdn.microsoft.com/en-us/library/e9etx778%28v=vs.71%29.aspx http://www.gotw.ca/gotw/066.htm Second, I have seen #ifndef pragmas in some of the examples, e.g., in the body of function myadvance_dispatch you have: { #ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS Distance n_max = n; #endif CONTRACT_LOOP( while(n++) ) { CONTRACT_LOOP_VARIANT( const( n_max, n ) n_max - n ) --i; } } I am not sure if the necessity to use this conditional code would occur often, but if so, perhaps the code would be slightly more clear if instead the conditional code would be wrapped in an additional macro, like MFC did with DEBUG_ONLY macro: { CONTRACT_CONFIG_LOOP_VARIANT_ONLY( Distance n_max = n ); CONTRACT_LOOP( while(n++) ) { CONTRACT_LOOP_VARIANT( const( n_max, n ) n_max - n ) --i; } } That is, macro CONTRACT_CONFIG_LOOP_VARIANT_ONLY is defined as: #ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS #define CONTRACT_CONFIG_LOOP_VARIANT_ONLY(ARG) ARG #else #define CONTRACT_CONFIG_LOOP_VARIANT_ONLY(ARG) #endif Although I am not sure if a similar trick would be possible with the definition like: CONTRACT_FUNCTION( template( typename T ) requires( Addable<T> #ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS // Equality only for postconditions. , boost::EqualityComparable<T> #endif ) (T) (add) ( (T) x, (T) y ) postcondition( auto result = return, result == x + y ) ) { return x + y; } Regards, &rzej

On Fri, Sep 2, 2011 at 5:45 PM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
Comments are always welcome :)
Hi Lorenzo, The number of examples is impressive. It is a pleasure to observe your library growing at this pace. I would like to suggest two things. I could not see from the examples, if the library is capable of supporting "function try blocks" in constructor and destructor definitions. This is what I mean. http://msdn.microsoft.com/en-us/library/e9etx778%28v=vs.71%29.aspx http://www.gotw.ca/gotw/066.htm
I have added this to my TO-DO. Currently this is not possible and I don't know if I can implement it but I will look into it (it's yet another good suggestion you made, thanks). The point is that my macros can essentially expand to any code that might be needed for this but how do I implement this in C++ even if I am willing to program (or have the macros expand to) a lot of boiler-plate code? I need to look into what can be done.
Second, I have seen #ifndef pragmas in some of the examples, e.g., in the body of function myadvance_dispatch you have:
{ #ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS Distance n_max = n; #endif CONTRACT_LOOP( while(n++) ) { CONTRACT_LOOP_VARIANT( const( n_max, n ) n_max - n ) --i; } }
I am not sure if the necessity to use this conditional code would occur often, but if so, perhaps the code would be slightly more clear if instead the conditional code would be wrapped in an additional macro, like MFC did with DEBUG_ONLY macro:
{ CONTRACT_CONFIG_LOOP_VARIANT_ONLY( Distance n_max = n );
CONTRACT_LOOP( while(n++) ) { CONTRACT_LOOP_VARIANT( const( n_max, n ) n_max - n ) --i; } }
In this case the conditional declaration of n_max is to avoid an "unused variable" warning when loop variants are disabled. However, you can simply program this differently: { Distance m = n; CONTRACT_LOOP( while(m++) ) { CONTRACT_LOOP_VARIANT( const( n, m ) n - m ) --i; } } or accept the warning, or use the pragma. This use case is really a programmers' choice and I wanted to show that using the pragma is one of the options (I will explain this in the docs).
That is, macro CONTRACT_CONFIG_LOOP_VARIANT_ONLY is defined as:
#ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS #define CONTRACT_CONFIG_LOOP_VARIANT_ONLY(ARG) ARG #else #define CONTRACT_CONFIG_LOOP_VARIANT_ONLY(ARG) #endif
Although I am not sure if a similar trick would be possible with the definition like:
CONTRACT_FUNCTION( template( typename T ) requires( Addable<T> #ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS // Equality only for postconditions. , boost::EqualityComparable<T> #endif ) (T) (add) ( (T) x, (T) y ) postcondition( auto result = return, result == x + y ) ) { return x + y; }
This use case is different then the above (more compelling). The issues here is that when programming contracts you quickly start using extra checks (and especially ==) which add additional requirements on generic types. For example, in this case T does not have to be EqualityComparable to program the body but you still want to program and check the postcondition when T happens to be EqualityComparable. I have been thinking to solve this issue by providing: namespace contract { temlate< typename T> bool equal(T const& left, T const& right) ... } equal will return true if T is not EqualityComparable and left == right if T is EqualityComparable. That way you can program the contracts using contract::equal(x, y) without introducing additional requirements on T at all but still checking the contract conditions for EqualityComparable types. I will also expand equal to handle containers (compare all elements of a vector, etc) and I will provide similar functions for other operations. All of these contract helper functions will be in a separate header <contract/utility.hpp>. I have not started to implement this yet. BTW, I am also wondering if it would be useful to implement a fully contracted version of the STL probably in contract::std: #include <contract/std/vector.hpp> #include <contract/std/algorithm.hpp> contract::std::vector<int> v; contract::std::for_each(v.begin(), v.end(), ...); I think Boost.Contract can essentially implement most/all of the interface contracts (preconditions, postconditions, invariants, and concepts) documented by the SGI: http://www.sgi.com/tech/stl/ Would such a contract::std be any useful? Thanks a lot for your comments! --Lorenzo

Andrzej Krzemienski wrote:
Comments are always welcome :) library growing at this pace. I would like to suggest two things. I could not see from the examples, if the library is capable of supporting "function try blocks" in constructor and destructor definitions. This is what I mean. http://msdn.microsoft.com/en-us/library/e9etx778%28v=vs.71%29.aspx http://www.gotw.ca/gotw/066.htm
I have implemented support for function-try-blocks and also for exception specifications. For example: http://svn.boost.org/svn/boost/sandbox/contract/libs/contract/doc/html2/cont... Preconditions, postconditions, and class invariants are checked outside function-try-blocks (N1962) and I do the same for exception specifications. Therefore, both function-try-blocks and exception specifications only catch exceptions thrown by the function body and not exceptions thrown by my library implementation (if there is an internal library error) or by a contract assertion failure*. (*) As I mentioned a few times before, in case a contract assertion is not checked to be true (because it is false or because the assertion checking throws), my library calls the contract broken handlers which call std::terminate (N1962). However, users can redefine the broken handlers to do whatever they wish including throwing an exception. In this case (which is not adviced and it is not the library's default behavior) the exception thrown by the broken contract assertion will /not/ be caught by the function-try-block (as per N1962) nor by the function exception specifications. Syntax: 1) Exception specifications are specified within the contract macros because they are part of the function declaration. 2) Function-try-blocks are specified outside the contract macros because they are part of the function definition. The only exception of this rule is for constructors with member initializers for which both the member initializers and function-try-block are specified within the macros (even if both the member initializers and the function-try-block are still part of the constructor definition). This is a (small?) limitation of my library which is caused by C++03 lack of delegating constructors and ultimately causes the limitation that constructors with member initializers need to be defined together with their declarations when the contract macros are used. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/contract-syntax-redesign-tp3563993p383072... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (3)
-
Andrzej Krzemienski
-
lcaminiti
-
Lorenzo Caminiti