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