Boost logo

Boost :

Subject: Re: [boost] [review][constrained_value] Review of ConstrainedValueLibrary begins today
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2008-12-05 18:37:41

Hola Robert!

----- Original Message -----
From: "Robert Kawulak" <robert.kawulak_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, December 05, 2008 11:40 AM
Subject: Re: [boost] [review][constrained_value] Review of ConstrainedValueLibrary begins today

> Salut Vicente, :)
>> From: vicente.botet
>> There is a thing that i don't like in the design, the fact
>> that you can change the constraint at runtime.
> If you use a constraint that works statically then there is no way to change it.
> It is bound to the constrained type.

>> I would prefer
>> to have two separated hierarchies, one for constrained values
>> that preserv its constraints, error handling, ... staticaly,
>> and one for those tyhe constraint can be changed at runtime.
> I wouldn't prefer to have two separate hierarchies with almost identical
> functionality and differing only in details.

Well we can have a single type that cover with the whole domain, but we will need more metaprogramming.
>> I expect that the preserving constrained values be
>> implemented in a more space and time efficient way.
> Did you find any problems with suboptimal work of the current implementation for
> the static cases?

I expect that a constrained integer will have the same size as an int, i.e. sizeof(int). Which is the size of an instance of the constrained class?
See below one possible implementation of static_constrained. Of course, the implementation is not complete.
>> For the constrained values that can change its constraint at
>> runtime I see two cases, the constraint is attached to the
>> instance, which is your case, or it attached to a type.
>> mutating_type :== by_instance | by_type
>> When attached to a type, the type needs to maintain the set
>> of instances. Instead of changing the type a split operation
>> can be provided resulting in a transfer of the instances
>> satisfying the new constraint to the new type. Of course this
>> meens more space and time consumming, but ...
> There was a similar idea on the users list and I'm still not convinced this
> leads to something good.
> If you request to change the constraint of a whole type and some instances don't
> obey your request, then what is the point in doing this?

I'm not requesting you to implement constrained values for which the user can change the constraint globaly at runtime. It was only explorating the domain. Instead of changing the constraint of a whole type I was suggesting to provide a split operation that takes the instances satisfying the new constraints and transfer them from the old type to the new type. I have no concrete use case in mind seen the implied performances for the split operation but perhaps this could be useful to someone.



template <
    typename ValueType,
    typename ConstraintPolicy = boost::function1<bool, const ValueType &>,
    typename ErrorPolicy = throw_exception<>
> struct constrained_type {
    typedef ValueType value_type;
    typedef ConstraintPolicy constraint_type;
    typedef ErrorPolicy error_handler_type;

    constrained_type() : cp_(), ep_() {}
    constrained_type(constraint_type c) : cp_(c) {}
    constrained_type(constraint_type c, error_handler_type eh) : cp_(c), ep_(eh) {}

    ConstraintPolicy cp_;
    ErrorPolicy ep_;

template <
    typename ConstrainedTraits
struct static_constrained {
    typedef typename ConstrainedTraits::type::value_type value_type;
    typedef typename ConstrainedTraits::type::constraint_type constraint_type;
    typedef typename ConstrainedTraits::type::error_handler_type error_handler_type;

    static_constrained(const value_type & v)
        : value_(v)
    { _initialize(); }

    const value_type & value() const
    { return value_; }

    operator const value_type & () const
    { return value(); }

    const constraint_type & constraint() const
    { return ConstrainedTraits::value.cp_; }

    const error_handler_type & error_handler() const
    { return ConstrainedTraits::value.ep_; }

    void _initialize()
        if( !constraint()(value()) )
            error_handler()(value(), value(), constraint());

    value_type value_;


struct even_traits {
    typedef constrained_type<int, is_even> type;
    static const type value;

const even_traits::type even_traits::value;

typedef static_constrained<even_traits> even_type;

int main() {
    even_type a(2);
    std::cout << "sizeof(even_type)=" << sizeof(even_type) << std::endl;
    even_type b(1); // throws

Boost list run by bdawes at, gregod at, cpdaniel at, john at