Boost logo

Boost :

Subject: Re: [boost] [review][constrained_value] Review ofConstrainedValueLibrary begins today
From: Robert Kawulak (robert.kawulak_at_[hidden])
Date: 2008-12-10 22:05:12


> From: vicente.botet

> >> * The operators have not always a sens for the application.
> >> For example,
> >> constrained<int, is_even> x;
> >> ++x;
> >>
> >> I would prefer to have a compile error in this particular
> >> case instead of an exception. It will be quite interesting to
> >> show how a user can catch this error at compile time and
> >> avoid this runtime error.
> >
> > Passing over presumable complexity of the implementation,
> this would be quite
> > inconsistent behaviour. Why "++x" should behave in a
> different way than "x +=
> > 1"?
>
> I'm not said that.

You haven't mentioned so far that you want *all* operators to be turned off. You
said "in this particular case", so I assumed you want "++x" to fail to compile
while "x += 1" to throw. Sorry for misinterpretation.

> > Then for the even object we should also ban, e.g., *=,
> although it perfectly
> > makes sense?
>
> It should be up to the user to choose if he want arithmetic
> operator for his
> constrained<int, is_even, throw_exception<>,
> with_arithmetic_operators>

I don't see much value in only giving an "all or nothing" option (since most of
the other operators may still be useful) and I don't think it would be
reasonable to implement possibility of selective exclusion of only some of the
operators.

> >> * constrained must be default constructible. The library
> >> should provide a mean to specify a default value. E. g.
> >> constrained<default<int, 1>, is_odd >
> >
> > I think this is too general utility to belong to this
> library (it's similar to
> > value_initialized in Boost.Utility).
>
> Maybe, this could be a general utility, but your library make
> some constrained values not default constructibles. What the
> user can do waiting for this utility?

Ask maintainer of Boost.Utility to add it? I think it is a better solution than
adding it somewhere where it doesn't belong...

> >> I think that it will more clear if instead of stating
> >> exclusion we state inclusion, and the default be true,
> >>
> >> So we can write
> >> typedef static_bounded<int, 0, 100, throw_exception<>,
> >> false, true>::type t;
> >
> > A value-initialised bool has the value of false. Therefore,
> bounds exclusion is
> > used rather than bounds inclusion, so the default is always
> "bounds included"
> > when the bounds inclusion indicators are default-constructed.
>
> Why do you talk about value initializetion. The parmeter have
> already a default value. It is enough to change the meaning
> of the boolean parameter.

For compile-time indicators of bounds exclusion/inclusion we have to rely on
default construction (we cannot initialise mpl::true_ with a bool value).
Run-time indicators have to behave the same way to allow for full
interchangeability, so default-constructed bool should represent the most common
use case. If we had inclusion indicators, the following:

        typedef within_bounds<int, int, bool, bool> dynamic_bounds;
        constrained<int, dynamic_bounds> x(dynamic_bounds(-10, 10));

Would construct x with the range (-10, 10) rather than [-10, 10]. We could make
within_bounds constructor take two extra arguments that default to true, but
then the same example with compile-time indicators would not compile.

Apart from that I consider the choice of inclusion vs. exclusion quite arbitrary
and there's no point in arguing which one is better.

> >> * The number of parameters of the bounded class is already
> to high.
> >
> > Most of them (ordered from most to least used) have default
> values, so I don't
> > think this is a serious problem. Your solution reduces them
> from 7 to 5, which
> > may be seen as not much... However, it looks interesting.
> >
> >> Even in this case the bool values are not enough declarative.
> >> It would even be beter to define two templates, open, close
> >> (see below)
> >> typedef static_bounded<int, open<0>, close<100> >::type t;
> >
> > I don't know if this is an optimal solution if for the most
> common case, when
> > the bounds are included, you have to write more than:
> >
> > typedef static_bounded<int, 0, 100>::type t;
>
> When I read static_bounded<int, 0, 100> I need to know which
> are the defaults to know if the bound are in or not. When a
> read static_bounded<int, open<0>, close<100> > there is no
> issue. It is explicit. What is more readable |1,100| or
> [1,100], (1,100)?

It is readable, but not always readability == usability. I'll try to make a
complete implementation and see how it works first.

> >> *Date type would show the change upper bound at runtime, and
> >> see how the values of a variable (month) impact the
> >> constraints on another variable (day).
> >
> > Might be a nice example, let me consider this.
>
> I think this example is a must. Every one think on the Date
> data type when talking abount constrained values.

I wouldn't call it "a must", it's simply one of many use cases and it doesn't
show any functionality of the library that is not already covered in the
tutorial. However, it's quite nice and, as I said, I'll think about adding it
(after trying to implement it).

Best regards,
Robert


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk