$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: [boost] [contract] concepts (was "Contract Programming Library")
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-04-15 11:50:26
On Wed, Feb 17, 2010 at 4:05 AM, Andrzej Krzemienski <akrzemi1_at_[hidden]> wrote:
>> > it is inevitable, etc., but.. read on. I know at least one library in
>> > Boost that also spoils function declarations in order to provide
>> > additional functionality: Concept Check library; they may be others
>> > too (MPL?).
>> > My suggestion is that if there are (or will be) libraries that require
>> > spoiling function declarations, they should all provide the same
>> > "spoiled" syntax. Otherwise I will be always asking "how do I declare
>> > a function in this library?". It would be very convenient if Boost
>> > provided one alternative function definition syntax that when used
>> > would enable all its libraries to work.
>>
>> I agree. However, in the past I did look into harmonizing my library
>> API with the ones of Boost.ConceptCheck and/or Boost.Parameter but it
>> did not seem feasible... I will double check it.
>
> This is not only about clarity. As a super-correct programmer I may want to
> apply both concept checking and pre-/post-conditions checking to my functions.
>
> Perhaps, if the 'compromise' syntax is possible, it requires changing
> concept-checking library.
I have verified that it is possible to use Boost.ConceptCheck together
with the current implementation of Boost.Contract as shown below. I
will look into doing something similar also for Boost.Parameter.
#include <boost/concept_check.hpp>
#include <boost/concept/requires.hpp>
#include <contract.hpp>
#include <iostream>
struct x {
CONTRACT_CLASS( (x) )
template<typename T>
BOOST_CONCEPT_REQUIRES(
((boost::Integer<T>)),
(int))
f(const T& x)
CONTRACT_FUNCTION(
(public) (template)( (typename)(T) )
(int) (f)( (const T&)(x) )
(precondition) ({
CONTRACT_ASSERT( x >= 0 );
})
(postcondition) (result) ({
CONTRACT_ASSERT( result == x );
})
(body) ({
return x;
}) )
};
int main() {
x xx;
std::cout << xx.f(123) << std::endl; // OK: Passes both
concept and contract checks.
// std::cout << xx.f(1.23) << std::endl; // Error: Fails
concept check (compile-time).
// std::cout << xx.f(-123) << std::endl; // Error: Fails
contract precondition check (run-time).
return 0;
}
This works because CONTRACT_FUNCTION() follows the function
declaration which can be spoiled by BOOST_CONCEPT_REQUIRES() as usual
to support concepts. However, I am planning to change
CONTRACT_FUNCTION() so the function declaration tokens do not need to
be repeated and I will add concept support following ConceptC++
syntax:
CONTRACT_FUNCTION(
(public) (template)( (typename)(T) )
(requires)( (boost::Integer<T>) )
(int) (f)( (const T&)(x) )
(precondition)( (x >= 0) )
(postcondition)(result)( (result == x) )
({
return x;
}) )
This will call Boost.ConceptCheck behind the scenes. Even after this
change to CONTRACT_FUNCTION(), Boost.Contract will still provide a
CONTRACT_FUNCTION_DEF() that will follow the function declaration (as
the current implementation of CONTRACT_FUNCTION() does). Therefore,
the example above where Boost.ConceptCheck is used directly can still
be programmed using the DEF() macro.
Lorenzo