Ranged type mini-library submission

There has been some discussion previously on this list for a ranged type. My personal desire was to have new double types in the ranges [0.0, 1.0) and [0.0, 1.0] among other things. There are several other uses that I can imagine. Feel free to rip this apart or do whatever you want. #include <float.h> #include <assert.h> namespace boost { // a simple range class template<class policy> class range { public: typedef range<policy> self; typedef typename policy::value value; range() : m(min()) { } range(const self& x) : m(x) { } range(const value& x) { m = rangeAssert(x); } static const value min() { return policy::min(); } static const value max() { return policy::max(); } operator value() { return m; } self& operator=(const self& x) { m = x; return *this; } self& operator=(const value& x) { m = rangeAssert(x); return *this; } const value& rangeAssert(const value& x) const { assert(x <= max()); assert(x >= min()); return x; }; private: value m; }; // some range policies struct RangePolicyZeroToOne { typedef double value; static const value min() { return 0.0; }; static const value max() { return 1.0; }; }; struct RangePolicyZeroToBelowOne { typedef double value; static const value min() { return 0.0; }; static const value max() { return 1.0 - DBL_EPSILON; }; }; struct RangePolicyPercent { typedef double value; static const value min() { return 0.0; }; static const value max() { return 100.0; }; }; struct RangePolicyDegrees { typedef double value; static const value min() { return 0.0; }; static const value max() { return 360.0 - DBL_EPSILON; }; }; struct RangePolicyRadians { typedef double value; static const value min() { return 0.0; }; static const value max() { return (2 * PI) - DBL_EPSILON; }; }; template <typename T, T min_T, T max_T> struct StaticRange { typedef T value; static const value min() { return min_T; }; static const value max() { return max_T; }; } // some sample types made with ranges typedef range<RangePolicyZeroToOne> Probability; typedef range<RangePolicyZeroToBelowOne> Distribution; typedef range<RangePolicyPercent> Percent; typedef range<RangePolicyDegrees> Degrees; typedef range<RangePolicyRadians> Radians; typedef range<RangePolicyStatic<int, 0, 11> > Month; typedef range<RangePolicyStatic<int, 0, 364> > DayOfTheYear; typedef range<RangePolicyStatic<int, 0, 6> > DayOfTheWeek; typedef range<RangePolicyStatic<char, 'a', 'z'> > LowerCaseLetter; typedef range<RangePolicyStatic<char, 'A', 'Z'> > UpperCaseLetter; typedef range<RangePolicyStatic<char, '0', '9'> > NumberChar; }; by Christopher Diggins licensed under the Boost software license http://www.cdiggins.com http://www.heron-language.com

what is >> expected to do if the number input it "out of range"? can we, for example, write cin >> month; (see below for definition of month)? should this be using numeric_limits<T>::epsilon() (instead of DBL_EPSILON) and would that even work for numbers larger than 2.0? At Friday 2004-05-14 14:08, you wrote:
There has been some discussion previously on this list for a ranged type. My personal desire was to have new double types in the ranges [0.0, 1.0) and [0.0, 1.0] among other things. There are several other uses that I can imagine. Feel free to rip this apart or do whatever you want.
#include <float.h> #include <assert.h>
namespace boost { // a simple range class template<class policy> class range { public: typedef range<policy> self; typedef typename policy::value value; range() : m(min()) { } range(const self& x) : m(x) { } range(const value& x) { m = rangeAssert(x); } static const value min() { return policy::min(); } static const value max() { return policy::max(); } operator value() { return m; } self& operator=(const self& x) { m = x; return *this; } self& operator=(const value& x) { m = rangeAssert(x); return *this; } const value& rangeAssert(const value& x) const { assert(x <= max()); assert(x >= min()); return x; }; private: value m; };
// some range policies struct RangePolicyZeroToOne { typedef double value; static const value min() { return 0.0; }; static const value max() { return 1.0; }; };
struct RangePolicyZeroToBelowOne { typedef double value; static const value min() { return 0.0; }; static const value max() { return 1.0 - DBL_EPSILON; }; };
struct RangePolicyPercent { typedef double value; static const value min() { return 0.0; }; static const value max() { return 100.0; }; };
struct RangePolicyDegrees { typedef double value; static const value min() { return 0.0; }; static const value max() { return 360.0 - DBL_EPSILON; }; };
struct RangePolicyRadians { typedef double value; static const value min() { return 0.0; }; static const value max() { return (2 * PI) - DBL_EPSILON; }; };
template <typename T, T min_T, T max_T> struct StaticRange { typedef T value; static const value min() { return min_T; }; static const value max() { return max_T; }; }
// some sample types made with ranges typedef range<RangePolicyZeroToOne> Probability; typedef range<RangePolicyZeroToBelowOne> Distribution; typedef range<RangePolicyPercent> Percent; typedef range<RangePolicyDegrees> Degrees; typedef range<RangePolicyRadians> Radians; typedef range<RangePolicyStatic<int, 0, 11> > Month; typedef range<RangePolicyStatic<int, 0, 364> > DayOfTheYear; typedef range<RangePolicyStatic<int, 0, 6> > DayOfTheWeek; typedef range<RangePolicyStatic<char, 'a', 'z'> > LowerCaseLetter; typedef range<RangePolicyStatic<char, 'A', 'Z'> > UpperCaseLetter; typedef range<RangePolicyStatic<char, '0', '9'> > NumberChar; };
by Christopher Diggins licensed under the Boost software license
http://www.cdiggins.com http://www.heron-language.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

----- Original Message ----- From: "Victor A. Wagner Jr." <vawjr@rudbek.com> To: <boost@lists.boost.org> Sent: Saturday, May 15, 2004 9:10 AM Subject: Re: [boost] Ranged type mini-library submission
what is >> expected to do if the number input it "out of range"? can we, for example, write cin >> month; (see below for definition of month)?
I am of the loose opinion that we shouldn't worry around with input/output operators for the range type. I am flexible on this though.
should this be using numeric_limits<T>::epsilon() (instead of DBL_EPSILON) and would that even work for numbers larger than 2.0?
Good point, I am working on fixing that. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

christopher diggins wrote:
should this be using numeric_limits<T>::epsilon() (instead of DBL_EPSILON) and would that even work for numbers larger than 2.0?
Good point, I am working on fixing that.
This doesn't seem like the best way to get this result. If I try to create an interval of [0, 1e100), this won't work; 1e100 - numeric_limits<T>::epsilon() is very likely to be 1e100, which would let me (incorrectly) assign 1e100 to such a constrained value. It seems to me that whether one end of an interval is open or closed corresponds to whether or not you use strict less-than/greater than, or less-than-or-equal/greater-than-or-equal. A value is in [0, 1e100) if (0 <= value && value < 1e100) is true. This is correct regardless of the type of value (assuming it provides < and <=, which is reasonable to assume for any type you're going to build an interval out of). To implement this, you could introduce another policy that controls how the min and max values are compared to the value. // prototype of the interval policy: template<typename T> struct interval_policy { static bool check_min(T value, T min); static bool check_max(T value, T max); }; // concrete cases: template<typename T> struct open_policy { static bool check_min(T value, T min) { return value > min; } static bool check_max(T value, T max) { return value < max; } }; template<typename T> struct closed_policy { static bool check_min(T value, T min) { return value >= min; } static bool check_max(T value, T max) { return value <= max; } }; You let the user specify an interval policy for the upper part and the lower part of the interval. Then your error check becomes: if (!lower_policy::check_min(value, min())) { // min_violation handler here } if (!upper_policy::check_max(value, max())) { // max_violation handler here } (A variation might revolve around letting a user specify std::less or std::less_equal.) But doing it this way we introduce two new polic arguments; maybe that's not so good. Another approach might be to change the definition of the constraints_policy itself so that it is responsible for the validation. You give it a member function called validate() which is expected to return true if the value is good, false otherwise. A variation on this approach would have it a return a value. The advantage of this variation would be that a policy could change a value to something legal and return it. For example, I could specify the interval [0, 10], and set it up so that if I assigned 11 to a variable of this type, it could clamp it to 10 rather than signal an error. (So far, the option to change an illegal value to a legal one and continue has not been mentioned, but it seems like a reasonable thing to want to do.) This approach also allows things that weren't part of the original idea, so I'm not sure what you'd think of them. For example, I could create a policy that allows even numbers only (not sure why I'd want that, but it would be possible). What do you think? Bob

----- Original Message ----- From: "Robert Bell" <belvis@imageworks.com> To: <boost@lists.boost.org> Sent: Sunday, May 16, 2004 7:02 PM Subject: [boost] Re: Ranged type mini-library submission
christopher diggins wrote:
should this be using numeric_limits<T>::epsilon() (instead of DBL_EPSILON) and would that even work for numbers larger than 2.0?
Good point, I am working on fixing that.
This doesn't seem like the best way to get this result. If I try to create an interval of [0, 1e100), this won't work; 1e100 - numeric_limits<T>::epsilon() is very likely to be 1e100, which would let me (incorrectly) assign 1e100 to such a constrained value.
It seems to me that whether one end of an interval is open or closed corresponds to whether or not you use strict less-than/greater than, or less-than-or-equal/greater-than-or-equal. A value is in [0, 1e100) if
(0 <= value && value < 1e100)
is true. This is correct regardless of the type of value (assuming it provides < and <=, which is reasonable to assume for any type you're going to build an interval out of).
To implement this, you could introduce another policy that controls how the min and max values are compared to the value.
// prototype of the interval policy: template<typename T> struct interval_policy { static bool check_min(T value, T min); static bool check_max(T value, T max); };
// concrete cases: template<typename T> struct open_policy { static bool check_min(T value, T min) { return value > min; } static bool check_max(T value, T max) { return value < max; } };
template<typename T> struct closed_policy { static bool check_min(T value, T min) { return value >= min; } static bool check_max(T value, T max) { return value <= max; } };
You let the user specify an interval policy for the upper part and the lower part of the interval. Then your error check becomes:
if (!lower_policy::check_min(value, min())) { // min_violation handler here } if (!upper_policy::check_max(value, max())) { // max_violation handler here }
(A variation might revolve around letting a user specify std::less or std::less_equal.)
But doing it this way we introduce two new polic arguments; maybe that's not so good.
Another approach might be to change the definition of the constraints_policy itself so that it is responsible for the validation. You give it a member function called validate() which is expected to return true if the value is good, false otherwise. A variation on this approach would have it a return a value. The advantage of this variation would be that a policy could change a value to something legal and return it. For example, I could specify the interval [0, 10], and set it up so that if I assigned 11 to a variable of this type, it could clamp it to 10 rather than signal an error. (So far, the option to change an illegal value to a legal one and continue has not been mentioned, but it seems like a reasonable thing to want to do.)
This approach also allows things that weren't part of the original idea, so I'm not sure what you'd think of them. For example, I could create a policy that allows even numbers only (not sure why I'd want that, but it would be possible).
What do you think?
Bob
You bring up an excellent point. I like the idea of having the policy do the verification itself. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

At Saturday 2004-05-15 16:35, you wrote:
----- Original Message ----- From: "Victor A. Wagner Jr." <vawjr@rudbek.com> To: <boost@lists.boost.org> Sent: Saturday, May 15, 2004 9:10 AM Subject: Re: [boost] Ranged type mini-library submission
what is >> expected to do if the number input it "out of range"? can we, for example, write cin >> month; (see below for definition of month)?
I am of the loose opinion that we shouldn't worry around with input/output operators for the range type. I am flexible on this though.
Obviously,I wouldn't have asked if I didn't think it were important. IMO the C founders were so dead set against strong typing that they ignored (and taught almost an entire generation of programmers) to ignore the concept. So now we have a language in which I cannot reasonably ensure mathematical limits on the range of numbers I need to play with. I guess what I'm asking is: if you cannot input or output it, what good is it?
should this be using numeric_limits<T>::epsilon() (instead of DBL_EPSILON) and would that even work for numbers larger than 2.0?
Good point, I am working on fixing that.
Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On Wed, 19 May 2004 20:43:05 -0700, Victor A. Wagner Jr. wrote
I guess what I'm asking is:
if you cannot input or output it, what good is it?
By default you will get the output operator of the underlying value type which in my experience should normally suffice. Or is there some additional functionality you had in mind? Jeff

At Thursday 2004-05-20 05:21, you wrote:
On Wed, 19 May 2004 20:43:05 -0700, Victor A. Wagner Jr. wrote
I guess what I'm asking is:
if you cannot input or output it, what good is it?
By default you will get the output operator of the underlying value type which in my experience should normally suffice. Or is there some additional functionality you had in mind?
not for output. for input it should fail if the input would fail the value input would fail rangeAssert.
Jeff _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On Thu, 20 May 2004 07:14:33 -0700, Victor A. Wagner Jr. wrote
By default you will get the output operator of the underlying value type which in my experience should normally suffice. Or is there some additional functionality you had in mind?
not for output. for input it should fail if the input would fail the value input would fail rangeAssert.
Ok, I see. Given the policy-based nature of the error handling this could be a bit tricky. However, I think this is a use case that argues for a consistent is_valid method on the constraint_policy. This way we can write one operator>> that can stream into the underlying type, check the validaty prior to attemting to set the value, and then set the ios flags on failure. Another problem this use case brings up is how to construct these... Jeff

On Fri, 14 May 2004 17:08:50 -0400, christopher diggins wrote
There has been some discussion previously on this list for a ranged type. My personal desire was to have new double types in the ranges [0.0, 1.0) and [0.0, 1.0] among other things. There are several other uses that I can imagine. Feel free to rip this apart or do whatever you want.
Did you see this post? http://lists.boost.org/MailArchives/boost/msg64485.php Very similar to yours, but policy class also allows for customization of the error handling. So instead of forcing an assert you can throw an exception, ignore it, log it, whatever. We've had several discussions of a uses for these constrained types. Perhaps you (or someone else) should boostify it? Jeff

----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Saturday, May 15, 2004 10:02 AM Subject: Re: [boost] Ranged type mini-library submission
On Fri, 14 May 2004 17:08:50 -0400, christopher diggins wrote
There has been some discussion previously on this list for a ranged type. My personal desire was to have new double types in the ranges [0.0, 1.0) and [0.0, 1.0] among other things. There are several other uses that I can imagine. Feel free to rip this apart or do whatever you want.
Did you see this post?
http://lists.boost.org/MailArchives/boost/msg64485.php
Very similar to yours, but policy class also allows for customization of the error handling. So instead of forcing an assert you can throw an exception, ignore it, log it, whatever.
Embarassingly enough, I looked at it briefly, then I jumped to the mistaken conclusion that it couldn't handle doubles so I rolled my own. After rereading it I realized you have a very elegant piece of code there!
We've had several discussions of a uses for these constrained types. Perhaps you (or someone else) should boostify it?
Jeff
I shall attempt to do so. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Sat, 15 May 2004 19:31:57 -0400, christopher diggins wrote
We've had several discussions of a uses for these constrained types. Perhaps you (or someone else) should boostify it?
Jeff
I shall attempt to do so.
That would be great, thx. Of course, I'll help however I can. Jeff

Here is my latest range.hpp file, I should probably change the name back to constrained_value because of the conflict with iterator ranges? I am a first time boost contributor , so I would appreciate comments on my style, and whether this file overextends its intended scope. To Jeff Garland: do you want me to be fully compatible with your existing constrained_value type, so that you can link this in without rewriting a thing? Thanks to all in advance. /* range.hpp Boost range type mini-library based on the constrained_value type by Jeff Garland, http://www.crystalclearsoftware.com/ modified and enhanced by Christopher Diggins http://www.cdiggins.com license available at http://www.boost.org/LICENSE_1_0.txt */ #ifndef BOOST_RANGE_HPP #define BOOST_RANGE_HPP // TEMP: my preference is to disallow silent casts to range // the default will have to decided upon by consensus #define BOOST_RANGE_SILENT_CASTS 1 // you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif #include <limits> namespace boost { namespace range { using namespace std; namespace policies { // some common policies for range types static inline double less_than(double d) { return (1.0 - numeric_limits<double>::epsilon()) * d; } template<typename T> struct root { typedef T value; static void on_error(T value, T min, T max) { cerr << "range violation: " << value << " outside of range " << min << " to " << max << endl; } }; struct unsigned_double : root<double> { static const value min() { return 0.0; }; }; struct zero_to_one_inclusive : public unsigned_double { static const value max() { return 1.0; }; }; struct zero_to_one_exclusive : public unsigned_double { static const value max() { return less_than(1.0); }; }; struct percent : public unsigned_double { static const value max() { return 100.0; }; }; struct degrees : public unsigned_double { static const value max() { return less_than(360.0); }; }; const double PI = 3.1415926535897; struct radians : public unsigned_double { static const value max() { return less_than(2 * PI); }; }; template <typename T, T min_T, T max_T> struct simple : root<T> { static const value min() { return min_T; }; static const value max() { return max_T; }; }; template<int base> struct whole_number : simple<unsigned short int, 0, base - 1> { }; }; // a simple range class template<class policy> class range { public: typedef range<policy> self; typedef typename policy::value value; range() : m(min()) { } range(const self& x) { m = x.get_value(); } #ifdef BOOST_RANGE_SILENT_CASTS range(value x) { assign(x); } #endif static const value min() { return policy::min(); } static const value max() { return policy::max(); } const value get_value() const { return m; } operator value() { return m; } self& operator=(const self& x) { m = x; return *this; } #ifdef BOOST_RANGE_SILENT_CASTS self& operator=(value x) { assign(x); return *this; } #endif void assign(const value& x) { #ifdef BOOST_RANGE_CHECKING_ON { if (x+1 < min()+1) { policy::on_error(x, min(), max()); return; } if (x > max()) { policy::on_error(x, min(), max()); return; } } #endif m = x; } private: value m; }; // some common types expressed as ranges typedef range<policies::zero_to_one_inclusive> probability; typedef range<policies::zero_to_one_exclusive> distribution; typedef range<policies::percent> percent; typedef range<policies::degrees> degrees; typedef range<policies::radians> radians; typedef range<policies::whole_number<24> > hour; typedef range<policies::whole_number<60> > minute; typedef range<policies::whole_number<60> > second; typedef range<policies::whole_number<10> > decimal_digit; typedef range<policies::whole_number<16> > hex_digit; typedef range<policies::whole_number<8> > octal_digit; typedef range<policies::whole_number<7> > day_of_week; typedef range<policies::whole_number<12> > greg_month; typedef range<policies::whole_number<365> > greg_day_of_year; }; }; #endif // BOOST_RANGE_HPP Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

Hi, Just a quick remark. Why don't you split policies into different categories? Error handling policy is orthogonal with constraint policy. The more reasonable definition would be template< typename ConstraintPolicy, typename ErrorPolicy=default_error_policy> class range { //... }; In regards of naming, contrained_value would be much better. Regards. Pavol On Sat, May 15, 2004 at 10:37:43PM -0400, christopher diggins wrote:
Here is my latest range.hpp file, I should probably change the name back to constrained_value because of the conflict with iterator ranges? I am a first time boost contributor , so I would appreciate comments on my style, and whether this file overextends its intended scope.
To Jeff Garland: do you want me to be fully compatible with your existing constrained_value type, so that you can link this in without rewriting a thing?
Thanks to all in advance.

On Sat, 15 May 2004 22:37:43 -0400, christopher diggins wrote
Here is my latest range.hpp file, I should probably change the name back to constrained_value because of the conflict with iterator ranges?
I agree with Pavol, I think constrained_value is a better name for the simple reason that the resulting type doesn't hold a range. Not to mention that range is already very overloaded...
I am a first time boost contributor , so I would appreciate comments on my style, and whether this file overextends its intended scope.
Probably more work than you were thinking when you volunteered ;-) So here's the steps we will need to take: 1) Agree on a final interfaces / name. 2) Decide where this should go in boost. Could be in utility, but I think I would it would be it's own little mini-library. 3) Write docs and tests (We can convert some of my date_time tests as a start) 4) Request and complete a fast-track review. Maybe we should create a place in the boost-sandbox to collaborate on this?
To Jeff Garland: do you want me to be fully compatible with your existing constrained_value type, so that you can link this in without rewriting a thing?
No, not at all. I'll rework date_time to be compatible.
/* range.hpp ...snip... // TEMP: my preference is to disallow silent casts to range // the default will have to decided upon by consensus #define BOOST_RANGE_SILENT_CASTS 1
If we are going to allow this option it should be a policy not a macro. For date_time I want the automatic conversion. But I can imagine that perhaps in the same program I might have another type which I don't want this behavior.
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
#include <limits>
namespace boost { namespace range { using namespace std;
namespace policies
Strikes me as overkill to have another namespace for the policy classes.
{ // some common policies for range types
static inline double less_than(double d) { return (1.0 - numeric_limits<double>::epsilon()) * d; }
template<typename T> struct root {
^^^^ cerr_base_policy?
typedef T value; static void on_error(T value, T min, T max) { cerr << "range violation: " << value << " outside of range " << min << " to " << max << endl; } };
....snip...
// a simple range class template<class policy> class range {
I'm starting to think that Pavel is correct about the orthogonal policies. Maybe we need this to be something like: template< typename ConstraintPolicy, typename ErrorPolicy=default_error_policy, typename ImplicitConversionPolicy=allow_implicit_conversion, typename CheckingPolicy=checking_on> class constrained_value { The downside I see here is that errors get much uglier. Jeff

----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Sunday, May 16, 2004 9:35 AM Subject: Re: [boost] Ranged type mini-library submission
On Sat, 15 May 2004 22:37:43 -0400, christopher diggins wrote
Here is my latest range.hpp file, I should probably change the name back to constrained_value because of the conflict with iterator ranges?
I agree with Pavol, I think constrained_value is a better name for the simple reason that the resulting type doesn't hold a range. Not to mention that range is already very overloaded...
Yes, I am in agreement.
I am a first time boost contributor , so I would appreciate comments on my style, and whether this file overextends its intended scope.
Probably more work than you were thinking when you volunteered ;-) So here's the steps we will need to take: 1) Agree on a final interfaces / name. 2) Decide where this should go in boost. Could be in utility, but I think I it would be it's own little mini-library.
I agree.
3) Write docs and tests (We can convert some of my date_time tests as a start)
4) Request and complete a fast-track review. Maybe we should create a place in the boost-sandbox to collaborate on
Sounds good. this? Done, I have created a constrained_value folder and uploaded the lastest version of the file. http://groups.yahoo.com/group/boost/files/constrained_value/ [snip]
/* range.hpp ...snip... // TEMP: my preference is to disallow silent casts to range // the default will have to decided upon by consensus #define BOOST_RANGE_SILENT_CASTS 1
If we are going to allow this option it should be a policy not a macro. For date_time I want the automatic conversion. But I can imagine that perhaps in the same program I might have another type which I don't want this behavior.
I agree it would be better as a policy.
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING policy for only some types strikes me as rather pathological.
#include <limits>
namespace boost { namespace range { using namespace std;
namespace policies
Strikes me as overkill to have another namespace for the policy classes.
Agreed.
{ // some common policies for range types
static inline double less_than(double d) { return (1.0 - numeric_limits<double>::epsilon()) * d; }
template<typename T> struct root {
^^^^ cerr_base_policy?
Nice.
typedef T value; static void on_error(T value, T min, T max) { cerr << "range violation: " << value << " outside of range " << min << " to " << max << endl; } };
....snip...
// a simple range class template<class policy> class range {
I'm starting to think that Pavel is correct about the orthogonal policies. Maybe we need this to be something like:
Me too.
template< typename ConstraintPolicy, typename ErrorPolicy=default_error_policy, typename ImplicitConversionPolicy=allow_implicit_conversion, typename CheckingPolicy=checking_on> class constrained_value {
The downside I see here is that errors get much uglier.
I advocate no CheckingPolicy: template< typename ConstraintPolicy, typename ErrorPolicy=default_error_policy, typename ImplicitConversionPolicy=allow_implicit_conversion> class constrained_value { ... } Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Sun, May 16, 2004 at 11:07:22AM -0400, christopher diggins wrote:
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Sat, 15 May 2004 22:37:43 -0400, christopher diggins wrote
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING policy for only some types strikes me as rather pathological.
You may be right if all the range checking policy can do is signaling an error - I am not sure. But I can imagine applications where you'd like a saturating range checking policy, i.e. the input value is replaced by the maximum or minimum valid value. Or you need a periodic behaviour where the input value is projected onto an interval. OTOH, I may be falling into the trap of over-engineering. Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

On Sun, May 16, 2004 at 11:07:22AM -0400, christopher diggins wrote:
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Sat, 15 May 2004 22:37:43 -0400, christopher diggins wrote
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING
----- Original Message ----- From: "Christoph Ludwig" <cludwig@cdc.informatik.tu-darmstadt.de> To: <boost@lists.boost.org> Sent: Sunday, May 16, 2004 12:21 PM Subject: Re: [boost] Ranged type mini-library submission policy
for only some types strikes me as rather pathological.
You may be right if all the range checking policy can do is signaling an error - I am not sure. But I can imagine applications where you'd like a saturating range checking policy, i.e. the input value is replaced by the maximum or minimum valid value. Or you need a periodic behaviour where the input value is projected onto an interval.
OTOH, I may be falling into the trap of over-engineering.
You bring up a good point, but the conditional can also be introduced directly into the error policy. There are three options as I see it: 1) always apply check 2) have a macro as in the currrent version 3) have a separate policy for check The arguments against number three (that I see) are: - redundancy: conditional checking can be accomplished by the error policy. - increases complexity - introduces potential errors which would be very difficult to identify and track down It seems that the macro is not particularly attractive and could interfere with certain specialized usages of constrained types, and would be preferably dropped. Is this an accurate assesment? Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Sun, May 16, 2004 at 12:56:00PM -0400, christopher diggins wrote:
On Sun, May 16, 2004 at 11:07:22AM -0400, christopher diggins wrote:
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING
From: "Christoph Ludwig" <cludwig@cdc.informatik.tu-darmstadt.de> policy
for only some types strikes me as rather pathological.
You may be right if all the range checking policy can do is signaling an error - I am not sure. But I can imagine applications where you'd like a saturating range checking policy, i.e. the input value is replaced by the maximum or minimum valid value. Or you need a periodic behaviour where the input value is projected onto an interval.
OTOH, I may be falling into the trap of over-engineering.
You bring up a good point, but the conditional can also be introduced directly into the error policy.
It's my oversight. I didn't realize you were discussing the merits of *separate* policies for the range check and the reaction to any found violation of the range condition.
There are three options as I see it: 1) always apply check 2) have a macro as in the currrent version 3) have a separate policy for check
The arguments against number three (that I see) are: - redundancy: conditional checking can be accomplished by the error policy. - increases complexity - introduces potential errors which would be very difficult to identify and track down
It seems that the macro is not particularly attractive and could interfere with certain specialized usages of constrained types, and would be preferably dropped. Is this an accurate assesment?
I think so. Of course, any class implementing a range check policy can itself be parameterized by an error handling policy. But that's a different issue. Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

On Sun, 16 May 2004 11:07:22 -0400, christopher diggins wrote
Done, I have created a constrained_value folder and uploaded the lastest version of the file. http://groups.yahoo.com/group/boost/files/constrained_value/
Not that one, the other sandbox ;-) http://sourceforge.net/projects/boost-sandbox/
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING policy for only some types strikes me as rather pathological.
Well, if I've got my own class and I'm using the fixed size string class that also uses constrained_value I might accidently turn off the string range checking when I just wanted to turn off my classes range checking. As to using the error_policy to control this, it's not quite the same. With your current macro it ensures that no check is even performed. Replacing the error policy, the code will still do the checking. So if my goal was perfomance optimization than it is lost. I'm intrigued by the suggestion of a validation policy that could implement more that min/max checking. To do this and maintain the min/max functions for the range case we would probably have to do something 'clever' like this: template< class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true> class constrained_value : public constraints_policy { allowing the policy to define any client helper functions interfaces. In fact, some classes might want to expose an bool is_valid(value) function to allow checking the value without invoking the error policy. Jeff

----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Monday, May 17, 2004 9:02 AM Subject: Re: [boost] Ranged type mini-library submission
On Sun, 16 May 2004 11:07:22 -0400, christopher diggins wrote
Done, I have created a constrained_value folder and uploaded the lastest version of the file. http://groups.yahoo.com/group/boost/files/constrained_value/
Not that one, the other sandbox ;-)
// you can explicitly turn off range_checking #ifdef BOOST_RANGE_CHECKING_OFF #define BOOST_RANGE_CHECKING_ON 0 #else #define BOOST_RANGE_CHECKING_ON 1 #endif
Again what happens if I want to change it for some, but not all my constrained types.
On this point, I am not convinced that it is important to make this specifically a policy. I can only imagine the usage of this kind of switch for debug versus release code. Switching on a BOOST_RANGE_CHECKING
for only some types strikes me as rather pathological.
Well, if I've got my own class and I'm using the fixed size string class
Would it be acceptable that I post on my web site: http://www.cdiggins.com/constrained_value.hpp until we arrive at consensus, at which i point I submit it to the sandbox? policy that
also uses constrained_value I might accidently turn off the string range checking when I just wanted to turn off my classes range checking. As to using the error_policy to control this, it's not quite the same. With your current macro it ensures that no check is even performed. Replacing the error policy, the code will still do the checking. So if my goal was perfomance optimization than it is lost.
Yes it is agreed then, the macro goes.
I'm intrigued by the suggestion of a validation policy that could implement more that min/max checking. To do this and maintain the min/max functions for the range case we would probably have to do something 'clever' like this:
template< class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true> class constrained_value : public constraints_policy {
allowing the policy to define any client helper functions interfaces. In fact, some classes might want to expose an bool is_valid(value) function to allow checking the value without invoking the error policy.
I too like the idea of a validation policy. You propose an interesting technique but I am not convinced it is the best option for what we want. If constraints_policy does the validation then the error handling policy could just more easily be passed as an argument to the constraints policy. This leaves us with: template< class constraints_policy, bool implicit_conversion_policy = true> class constrained_value { ... } This seems to be the simplest possible thing that will work. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Mon, 17 May 2004 10:51:19 -0400, christopher diggins wrote
Would it be acceptable that I post on my web site: http://www.cdiggins.com/constrained_value.hpp until we arrive at consensus, at which i point I submit it to the sandbox?
No problem, it's just that we will probably get this developed and then we will have to wait awhile for a review slot. In the meantime it's easier to do a cvs checkout for various updates and such. But seriously, there's no rush...
I too like the idea of a validation policy. You propose an interesting technique but I am not convinced it is the best option for what we want. If constraints_policy does the validation then the error handling policy could just more easily be passed as an argument to the constraints policy.
Yep, I agree.
This leaves us with:
template< class constraints_policy, bool implicit_conversion_policy = true> class constrained_value { ... }
But I think you the 'min' and 'max' function requirement is now out of place on the core template. If you have a constrained range, then it makes sense, but if I'm checking for 'divisible by 4' then I'll be perplexed as to why I have to provide min and max in my constraints_policy class. However, if you derive from the constraints_policy it can provide any interfaces it wants to the user. Jeff

This leaves us with:
template< class constraints_policy, bool implicit_conversion_policy = true> class constrained_value { ... }
But I think you the 'min' and 'max' function requirement is now out of
----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Monday, May 17, 2004 11:29 AM Subject: Re: [boost] Ranged type mini-library submission [snip] place
on the core template. If you have a constrained range, then it makes sense, but if I'm checking for 'divisible by 4' then I'll be perplexed as to why I have to provide min and max in my constraints_policy class. However, if you derive from the constraints_policy it can provide any interfaces it wants to the user.
You are completely correct about min and max. So I removed them. How about exposing the constraints_policy as a public typedef (I just posted a version which does this). This is perhaps a good compromise? There are just so many problems that can arise from parameterized inheritance, I would like to avoid it if there is an acceptable alternative. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Mon, 17 May 2004 11:53:49 -0400, christopher diggins wrote
You are completely correct about min and max. So I removed them. How about exposing the constraints_policy as a public typedef (I just posted a version which does this). This is perhaps a good compromise?
No, not really. I wanted to be able to ask the type it's min and max if it is a range type. Now I suppose I can dig out the policy, but it's fairly cumbersome in comparison to just calling mytype::max().
There are just so many problems that can arise from parameterized inheritance, I would like to avoid it if there is an acceptable alternative.
Such as? I must have missed that section in MC++ design. And anyway, how would these issues apply here? Jeff

----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Monday, May 17, 2004 10:02 PM Subject: Re: [boost] Ranged type mini-library submission
On Mon, 17 May 2004 11:53:49 -0400, christopher diggins wrote
You are completely correct about min and max. So I removed them. How about exposing the constraints_policy as a public typedef (I just posted a version which does this). This is perhaps a good compromise?
No, not really. I wanted to be able to ask the type it's min and max if it is a range type. Now I suppose I can dig out the policy, but it's fairly cumbersome in comparison to just calling mytype::max().
There are just so many problems that can arise from parameterized inheritance, I would like to avoid it if there is an acceptable alternative.
Such as? I must have missed that section in MC++ design. And anyway, how would these issues apply here?
I detect some frustration, I mean you no disrespect, I hold your work and comments in very high esteem. I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well. The problem with parameter inheritance, as least in this case, is that it surprises programmers by causing an object to have an inconsistent interface. Most programmers when confronted with code such as mytype::max() expect that max will be available for all instances of mytype. On the other hand, mytype::get_constraints().max() is generally understood to not always be readily available in a parameterized type. I don't see how the advantage of the shorthand justifies the case for parameter inheritance here. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Tue, 18 May 2004 00:17:40 -0400, christopher diggins wrote
I detect some frustration, I mean you no disrespect, I hold your work and comments in very high esteem.
No frustration, sorry it transmitted that way. Your statement was very broad, and implied that there are 'many problems' inheriting a template parameter. And yet I see it done sucessfully all the time in modern C++. Since I'm basically unaware of 'problems' with this approach your statement hit me much like the ever recurring programming guildeline: "Don't use multiple inheritance because it might create problems". Complete bunk that needs to be corrected...
I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well.
Well, ok, but I still don't like it.
The problem with parameter inheritance, as least in this case, is that it surprises programmers by causing an object to have an inconsistent interface.
This is really a matter of documentation. If I get used to calling mytype1::get_constraints().max() to find the max then I'm going to use my handy code editor to propagate this code around. As soon as I hit mytype2 that doesn't have constraints with a max function I'll be just as stumped as if mytype2::max didn't compile. Then I start looking at the docs and code to figure out what went wrong. But then I shouldn't expect a type with a name like 'divisible_by_four' to necessarily have a min/max interface.
Most programmers when confronted with code such as mytype::max() expect that max will be available for all instances of mytype.
I assume here mytype refers to the constrained_value template? Because for a given user type generated from this template mytype::max will be available for all instances.
On the other hand, mytype::get_constraints().max() is generally understood to not always be readily available in a parameterized type.
Really? Let's say I've never seen the documentation for constrained_value and I'm just reading some code I didn't write. For me, I have to think for an extra nano-second ( little joke :) about the meaning of this code: mytype::get_constraints().max() I'm thinking let's see, a static function that returns an object with a max function. As opposed to just -- yeah, get the max. mytype::max()
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I'll turn it around the other way -- I don't see how the 'longhand' makes the interface any clearer. The interface still needs a description the user can understand. In any highly flexible template design this is always more difficult. One last point. By inheriting from the policy, we can both have our way. You can specilize your constraint policy to have a public method 'get_contraints' that returns an object and I can have my min/max. Now that's power ;-) Jeff

----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Tuesday, May 18, 2004 9:24 AM Subject: Re: [boost] Ranged type mini-library submission
On Tue, 18 May 2004 00:17:40 -0400, christopher diggins wrote
I detect some frustration, I mean you no disrespect, I hold your work and comments in very high esteem.
No frustration, sorry it transmitted that way. Your statement was very broad, and implied that there are 'many problems' inheriting a template parameter.
I should not have made such a sweeping statement.
And yet I see it done sucessfully all the time in modern C++.
Since I'm basically unaware of 'problems' with this approach your statement hit me much like the ever recurring programming guildeline: "Don't use multiple inheritance because it might create problems". Complete bunk
It definitely is a powerful technique that I have used often. I am very hesitant about using it in libraries destined for public consumption when there exist alternatives which are more intuitive for naive programmers. that
needs to be corrected...
I understand.
I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well.
Well, ok, but I still don't like it.
The problem with parameter inheritance, as least in this case, is that it surprises programmers by causing an object to have an inconsistent interface.
This is really a matter of documentation. If I get used to calling mytype1::get_constraints().max() to find the max then I'm going to use my handy code editor to propagate
code around. As soon as I hit mytype2 that doesn't have constraints with a max function I'll be just as stumped as if mytype2::max didn't compile. Then I start looking at the docs and code to figure out what went wrong. But
I respect that, but my concern in this instance is whether Joe Average programmer will like it and understand it quickly. this then
I shouldn't expect a type with a name like 'divisible_by_four' to necessarily have a min/max interface.
I don't doubt that someone of your level of expertise would figure things out quickly, but my concern is with the lowest common denominator of experience. We are writing a library for the public, not for ourselves.
Most programmers when confronted with code such as mytype::max() expect that max will be available for all instances of mytype.
I assume here mytype refers to the constrained_value template? Because for a given user type generated from this template mytype::max will be available for all instances.
On the other hand, mytype::get_constraints().max() is generally understood to not always be readily available in a parameterized type.
Really? Let's say I've never seen the documentation for constrained_value and I'm just reading some code I didn't write. For me, I have to think for an extra nano-second ( little joke :) about the meaning of this code:
mytype::get_constraints().max()
I'm thinking let's see, a static function that returns an object with a max function. As opposed to just -- yeah, get the max.
mytype::max()
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I'll turn it around the other way -- I don't see how the 'longhand' makes
I stand corrected, I should have said all parameterizations. the
interface any clearer. The interface still needs a description the user can understand. In any highly flexible template design this is always more difficult.
An interface, as I am using the term here, is the set of public functions and public fields. An inteface for a parameterized type is generally understood to have functions or fields whose type is variant on a parameter. It is not generally understood or assumed that functions may or may not exist in a parameterized type.
One last point. By inheriting from the policy, we can both have our way. You can specilize your constraint policy to have a public method 'get_contraints' that returns an object and I can have my min/max. Now that's power ;-)
Your technique is most definitely more powerful but I am still concerned for naive users. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Tue, 18 May 2004 09:59:05 -0400, christopher diggins wrote
It definitely is a powerful technique that I have used often. I am very hesitant about using it in libraries destined for public consumption when there exist alternatives which are more intuitive for naive programmers.
Well, I submit that if that attitude prevailed then the standard library as we know it would not exist. But I'm falling into the arguing in generalities trap...
I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well.
Well, ok, but I still don't like it.
I respect that, but my concern in this instance is whether Joe Average programmer will like it and understand it quickly.
Who is this Joe Average anyway -- is he related to Joe Sixpack ;-)
I start looking at the docs and code to figure out what went wrong. But then I shouldn't expect a type with a name like 'divisible_by_four' to necessarily have a min/max interface.
I don't doubt that someone of your level of expertise would figure things out quickly, but my concern is with the lowest common denominator of experience. We are writing a library for the public, not for ourselves.
Why would it be easier for me or Joe Sixpack to understand your variation of the interface? You state this as though it were fact, but what I'm saying is that for me your variation is harder to understand. I think Rob Stewart agrees. I refuse to assume that I know what Joe Sixpack can understand, but looking at this typedef: typedef constrained_value<policies::divisible_integer<2> > even_integer; I wouldn't even think to try and call even_integer::max, while with this one: typedef constrained_value<policies::ranged_integer<0,2> > zero_to_two; it makes perfect sense.
An interface, as I am using the term here, is the set of public functions and public fields. An inteface for a parameterized type is generally understood to have functions or fields whose type is variant on a parameter. It is not generally understood or assumed that functions may or may not exist in a parameterized type.
I think I finally understand your concern. But, the fact is, the entire design can be assailed on this point. As soon as I throw an exception when the value is out of range instead of logging an error the 'naive user' (the one that didn't read the documentation) will be in debug mode. And Joe didn't even get told by the compiler. The point is that the final generated type is the point of behavior documentation that most users see -- not the constrained_value template itself. I also think you dare to presume an awful lot about what your fellow programmers can and can't understand.
One last point. By inheriting from the policy, we can both have our way. You can specilize your constraint policy to have a public method 'get_contraints' that returns an object and I can have my min/max. Now that's power ;-)
Your technique is most definitely more powerful but I am still concerned for naive users.
Naive and power users will read the tutorial first if something doesn't work. I suggest we educate the naive users by writing good documentation and examples rather than constraining the design. Jeff

From: christopher diggins <cdiggins@videotron.ca>
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Mon, 17 May 2004 11:53:49 -0400, christopher diggins wrote
There are just so many problems that can arise from parameterized inheritance, I would like to avoid it if there is an acceptable alternative.
Such as? I must have missed that section in MC++ design. And anyway, how would these issues apply here?
I detect some frustration, I mean you no disrespect, I hold your work and comments in very high esteem.
I think you misunderstood. He was just trying to find out what left the bad taste in your mouth.
I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well.
The problem with parameter inheritance, as least in this case, is that it surprises programmers by causing an object to have an inconsistent interface. Most programmers when confronted with code such as mytype::max() expect that max will be available for all instances of mytype. On the other hand, mytype::get_constraints().max() is generally understood to not always be readily available in a parameterized type.
I don't understand mytype::get_constraints().max() to not always be available. If I wanted that information, I'd write that expression (instead of mytype::max()) and then be surprised when it didn't work. It's simple enough to require that the template parameter supply min() and max() so that derivation yields those functions in mytype's interface. Then, it's a moot point whether min() and max() are part of a static or non-static interface for mytype.
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I don't see that you've solved any problem with your approach. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Rob Stewart" <stewart@sig.com> To: <boost@lists.boost.org> Cc: <boost@lists.boost.org> Sent: Tuesday, May 18, 2004 9:42 AM Subject: Re: [boost] Ranged type mini-library submission [snip]
I just changed the code by removing the public constraints typedef and adding a static function get_constraints() so that it can be invoked using instances of an object as well.
The problem with parameter inheritance, as least in this case, is that it surprises programmers by causing an object to have an inconsistent interface. Most programmers when confronted with code such as mytype::max() expect that max will be available for all instances of mytype. On the other hand, mytype::get_constraints().max() is generally understood to not always be readily available in a parameterized type.
I don't understand mytype::get_constraints().max() to not always be available. If I wanted that information, I'd write that expression (instead of mytype::max()) and then be surprised when it didn't work.
When working with any parameterized type, it is natural to expect the return value of some functions to be of a type equal to a parameter. It is not natural to expect that the existance of methods to be conditional on the parameter.
It's simple enough to require that the template parameter supply min() and max() so that derivation yields those functions in mytype's interface. Then, it's a moot point whether min() and max() are part of a static or non-static interface for mytype.
The constrained_value type allows constraints which have nothing to do with min() and max() so requiring it in the parameter seems arbitrary.
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I don't see that you've solved any problem with your approach.
I am simply tryign to use parameterized types in a more manner that is more widely understood and fits the natural assumptions of programmers. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

From: christopher diggins <cdiggins@videotron.ca>
From: "Rob Stewart" <stewart@sig.com>
I don't understand mytype::get_constraints().max() to not always be available. If I wanted that information, I'd write that expression (instead of mytype::max()) and then be surprised when it didn't work.
When working with any parameterized type, it is natural to expect the return value of some functions to be of a type equal to a parameter. It is not natural to expect that the existance of methods to be conditional on the parameter.
It is natural to assume that a parameterizing type meets the requirements of the template upon which it is used. If those include supplying min() and max() functions, then there's no surprise if things break when the parameterizing type fails to meet its obligation.
It's simple enough to require that the template parameter supply min() and max() so that derivation yields those functions in mytype's interface. Then, it's a moot point whether min() and max() are part of a static or non-static interface for mytype.
The constrained_value type allows constraints which have nothing to do with min() and max() so requiring it in the parameter seems arbitrary.
I don't get it. Among the constraints are the minimum and maximum values the type may assume, right? Why wouldn't min() and max() be part of that interface?
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I don't see that you've solved any problem with your approach.
I am simply tryign to use parameterized types in a more manner that is more widely understood and fits the natural assumptions of programmers.
The desire to "dumb down" the interface is good until it bumps into other goals. Balance is the key. The question is what is more obvious to end users. I contend, with Jeff, that c_v.max() is more obvious and sensible than c_v_type::get_constraints().max(). That c_v.max() imposes a requirements on the parameterizing type, and that the parameterizing type is used as a base class, is not critical in my mind. The important thing is to document the requirements on the parameterizing type and on the constrained_value class template itself. You might have mentioned it in one of your posts, but I didn't see where the object returned by c_v_type::get_constraints() would get its minimum and maximum values. Of what type is that object? How was that type determined? (Note: I haven't looked at your code, just your posts.) The answers to those questions will be telling as to how much you've reduced what you perceive to be cognitive complexity among the design alternatives. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Rob Stewart" <stewart@sig.com>
From: christopher diggins <cdiggins@videotron.ca>
From: "Rob Stewart" <stewart@sig.com>
I don't understand mytype::get_constraints().max() to not always be available. If I wanted that information, I'd write that expression (instead of mytype::max()) and then be surprised when it didn't work.
When working with any parameterized type, it is natural to expect the return value of some functions to be of a type equal to a parameter. It is not natural to expect that the existance of methods to be conditional on the parameter.
It is natural to assume that a parameterizing type meets the requirements of the template upon which it is used. If those include supplying min() and max() functions, then there's no surprise if things break when the parameterizing type fails to meet its obligation.
Supplying min() and max() is not an implicit requirement on a constraints policy. If you had bothered to look at the code at http://www.cdiggins.com/constrained_value.hpp before jumping in this conversation and expressing your opinions, then you might have realized that.
It's simple enough to require that the template parameter supply min() and max() so that derivation yields those functions in mytype's interface. Then, it's a moot point whether min() and max() are part of a static or non-static interface for mytype.
The constrained_value type allows constraints which have nothing to do with min() and max() so requiring it in the parameter seems arbitrary.
I don't get it. Among the constraints are the minimum and maximum values the type may assume, right? Why wouldn't min() and max() be part of that interface?
Again, if you looked at the code posted: http://www.cdiggins.com/cv_test.cpp you would have realized that a constraint policy can represent things as diverse as modulo'ed integers or integers divisble by a given number.
I don't see how the advantage of the shorthand justifies the case for parameter inheritance here.
I don't see that you've solved any problem with your approach.
I am simply tryign to use parameterized types in a more manner that is more widely understood and fits the natural assumptions of programmers.
The desire to "dumb down" the interface is good until it bumps into other goals. Balance is the key. The question is what is more obvious to end users. I contend, with Jeff, that c_v.max() is more obvious and sensible than c_v_type::get_constraints().max(). That c_v.max() imposes a requirements on the parameterizing type, and that the parameterizing type is used as a base class, is not critical in my mind. The important thing is to document the requirements on the parameterizing type and on the constrained_value class template itself.
You might have mentioned it in one of your posts, but I didn't see where the object returned by c_v_type::get_constraints() would get its minimum and maximum values. Of what type is that object? How was that type determined? (Note: I haven't looked at your code, just your posts.) The answers to those questions will be telling as to how much you've reduced what you perceive to be cognitive complexity among the design alternatives.
I don't feel particularly inclined to respond to your questions or concerns until you invest at least the minimum of effort required to take a look at the code and read the other posts related to this topic. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

From: christopher diggins <cdiggins@videotron.ca>
From: "Rob Stewart" <stewart@sig.com>
From: christopher diggins <cdiggins@videotron.ca>
From: "Rob Stewart" <stewart@sig.com>
I don't understand mytype::get_constraints().max() to not always be available. If I wanted that information, I'd write that expression (instead of mytype::max()) and then be surprised when it didn't work.
When working with any parameterized type, it is natural to expect the return value of some functions to be of a type equal to a parameter. It is not natural to expect that the existance of methods to be conditional on the parameter.
It is natural to assume that a parameterizing type meets the requirements of the template upon which it is used. If those include supplying min() and max() functions, then there's no surprise if things break when the parameterizing type fails to meet its obligation.
Supplying min() and max() is not an implicit requirement on a constraints policy. If you had bothered to look at the code at http://www.cdiggins.com/constrained_value.hpp before jumping in this conversation and expressing your opinions, then you might have realized that.
Pardon me for assuming that design discussions take place before implementing code. You have posted various snippets and were discussing various things; I was working from that context.
It's simple enough to require that the template parameter supply min() and max() so that derivation yields those functions in mytype's interface. Then, it's a moot point whether min() and max() are part of a static or non-static interface for mytype.
The constrained_value type allows constraints which have nothing to do with min() and max() so requiring it in the parameter seems arbitrary.
I don't get it. Among the constraints are the minimum and maximum values the type may assume, right? Why wouldn't min() and max() be part of that interface?
Again, if you looked at the code posted: http://www.cdiggins.com/cv_test.cpp you would have realized that a constraint policy can represent things as diverse as modulo'ed integers or integers divisble by a given number.
Possibly, but you posted rapid fire changes before design discussions subsided on various points, so I didn't feel the need to repeatedly download and view the code.
The desire to "dumb down" the interface is good until it bumps into other goals. Balance is the key. The question is what is more obvious to end users. I contend, with Jeff, that c_v.max() is more obvious and sensible than c_v_type::get_constraints().max(). That c_v.max() imposes a requirements on the parameterizing type, and that the parameterizing type is used as a base class, is not critical in my mind. The important thing is to document the requirements on the parameterizing type and on the constrained_value class template itself.
You might have mentioned it in one of your posts, but I didn't see where the object returned by c_v_type::get_constraints() would get its minimum and maximum values. Of what type is that object? How was that type determined? (Note: I haven't looked at your code, just your posts.) The answers to those questions will be telling as to how much you've reduced what you perceive to be cognitive complexity among the design alternatives.
I don't feel particularly inclined to respond to your questions or concerns until you invest at least the minimum of effort required to take a look at the code and read the other posts related to this topic.
Fine. You can justify your belligerence all you like. I thought I made some cogent arguments, despite the possibility of being slightly off course. A simple course correction from you would have sufficed. Since you prefer to attack rather than engage me, I'll leave the discussion to you and Jeff. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Tue, 18 May 2004 13:06:12 -0400 (EDT), Rob Stewart wrote
I don't feel particularly inclined to respond to your questions or concerns until you invest at least the minimum of effort required to take a look at the code and read the other posts related to this topic.
Fine. You can justify your belligerence all you like. I thought I made some cogent arguments, despite the possibility of being slightly off course. A simple course correction from you would have sufficed.
I agree with Rob here, dismissing his point of view this this way was out of line. Ironically, Rob was playing the role of the naive user since he hadn't looked at the code. Anyway, you could simply post a small code snippet in your email that illustrated why your point of view without expecting him to keep up with the latest revision. Frankly, I hadn't even looked at the test_cv stuff until this morning when I was trying to make the conversation more concrete.
Since you prefer to attack rather than engage me, I'll leave the discussion to you and Jeff.
Please don't do that. All that will assure is an inferior design -- one that might not stand up to a review... Jeff

On Tue, 18 May 2004 13:06:12 -0400 (EDT), Rob Stewart wrote
I don't feel particularly inclined to respond to your questions or concerns until you invest at least the minimum of effort required to take a look at the code and read the other posts related to this topic.
Fine. You can justify your belligerence all you like. I thought I made some cogent arguments, despite the possibility of being slightly off course. A simple course correction from you would have sufficed.
I agree with Rob here, dismissing his point of view this this way was out of line. Ironically, Rob was playing the role of the naive user since he hadn't looked at the code. Anyway, you could simply post a small code snippet in your email that illustrated why your point of view without expecting him to keep up with the latest revision. Frankly, I hadn't even looked at the test_cv stuff until this morning when I was trying to make the conversation more concrete.
Since you prefer to attack rather than engage me, I'll leave the discussion to you and Jeff.
Please don't do that. All that will assure is an inferior design -- one
----- Original Message ----- From: "Jeff Garland" <jeff@crystalclearsoftware.com> To: <boost@lists.boost.org> Sent: Tuesday, May 18, 2004 1:24 PM Subject: Re: [boost] Ranged type mini-library submission that
might not stand up to a review...
Jeff
I am going to be recusing myself from submitting the constrained_value library to boost. Obviously the work I have done up until this point is in the public domain, so I welcome others to continue to build on the work so far. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

The latest version of the constrained_value type mini-library is available online at: http://www.cdiggins.com/constrained_value.hpp This version has taken into account many of the excellent recent suggestions made on the list so far. Is there a particular etiquette that I should be aware of when assigning credit and making ack's? Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

/* constrained_value.hpp Boost constrained_value type mini-library original authour: Jeff Garland, http://www.crystalclearsoftware.com/ modified by: Christopher Diggins http://www.cdiggins.com license available at http://www.boost.org/LICENSE_1_0.txt last modified: May 16, 2004 */ #ifndef BOOST_CV_HPP #define BOOST_CV_HPP // you can explicitly turn off constrained_value_checking #ifdef BOOST_CV_CHECKING_OFF #define BOOST_CV_CHECKING_ON 0 #else #define BOOST_CV_CHECKING_ON 1 #endif #include <boost/mpl/if.hpp> namespace boost { namespace cv { enum enum_violation { min_violation, max_violation }; template<typename T, T min_T, T max_T> struct integer_range_policy { typedef typename T value; static const value min() { return min_T; }; static const value max() { return max_T; }; }; struct default_error_policy { template<typename T> static void on_error(T value, T* field, T min, T max, enum_violation v) { throw; } }; template < class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true > class constrained_value { private: struct unused_struct { }; public: typedef constrained_value<constraints_policy, error_policy, implicit_conversion_policy> self; typedef typename constraints_policy::value value; typedef typename mpl::if_c<implicit_conversion_policy, value, unused_struct> value_parameter; constrained_value() : m(min()) { } constrained_value(const self& x) { m = x.get_value(); } constrained_value(value_parameter x) { assign(x); } static const value min() { return constraints_policy::min(); } static const value max() { return constraints_policy::max(); } const value get_value() const { return m; } operator value() { return m; } self& operator=(const self& x) { m = x; return *this; } self& operator=(value_parameter x) { assign(x); return *this; } void assign(unused_struct x) { } void assign(const value& x) { #ifdef BOOST_CV_CHECKING_ON { // +1 removes unsigned warnings if (x+1 < min()+1) { error_policy::on_error(x, &m, min(), max(), policies::min_violation); return; } if (x > max()) { error_policy::on_error(x, &m, min(), max(), policies::max_violation); return; } } #endif m = x; } private: value m; }; }; }; #endif // BOOST_CV_HPP

christopher diggins wrote: [ ... ]
template < class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true >
[...] I just noticed that the implicit_conversion_policy policy argument controls whether a raw value can be assigned to a constrained_value, but has nothing to say about whether a constrained_value can be constructed from a raw value or whether a constrained value can be converted to a raw value. Bob

----- Original Message ----- From: "Robert Bell" <belvis@imageworks.com> To: <boost@lists.boost.org> Sent: Sunday, May 16, 2004 6:53 PM Subject: [boost] Re: Ranged type mini-library submission
christopher diggins wrote:
[ ... ]
template < class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true >
[...]
I just noticed that the implicit_conversion_policy policy argument controls whether a raw value can be assigned to a constrained_value, but has nothing to say about whether a constrained_value can be constructed from a raw value or whether a constrained value can be converted to a raw value.
Bob
This was intentional. I am of the point of view that implicit widening conversions are not something that needs to be switched on/off. The reason I included the policy was so that I could implement constrained values that would not have implicit narrowing conversions which is a source of many errors in C++ code. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On 5/16/04 11:09 AM, "christopher diggins" <cdiggins@videotron.ca> wrote: [SNIP]
template<typename T, T min_T, T max_T> struct integer_range_policy { typedef typename T value; static const value min() { return min_T; }; static const value max() { return max_T; }; }; [SNIP] template < class constraints_policy, class error_policy = default_error_policy, bool implicit_conversion_policy = true
class constrained_value { private: struct unused_struct { }; public: typedef constrained_value<constraints_policy, error_policy, implicit_conversion_policy> self; typedef typename constraints_policy::value value; typedef typename mpl::if_c<implicit_conversion_policy, value, unused_struct> value_parameter; constrained_value() : m(min()) { } constrained_value(const self& x) { m = x.get_value(); } constrained_value(value_parameter x) { assign(x); } static const value min() { return constraints_policy::min(); } static const value max() { return constraints_policy::max(); } const value get_value() const { return m; } operator value() { return m; } self& operator=(const self& x) { m = x; return *this; } self& operator=(value_parameter x) { assign(x); return *this; } void assign(unused_struct x) { } void assign(const value& x) { #ifdef BOOST_CV_CHECKING_ON { // +1 removes unsigned warnings if (x+1 < min()+1) { error_policy::on_error(x, &m, min(), max(), policies::min_violation); return; } if (x > max()) { error_policy::on_error(x, &m, min(), max(), policies::max_violation); return; } } #endif m = x; } private: value m; }; }; };
Should those "value" types be more like "value_type" to reduce confusion on what that member is? -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

----- Original Message ----- From: "Daryle Walker" <darylew@hotmail.com> To: "Boost mailing list" <boost@lists.boost.org> Sent: Saturday, May 22, 2004 1:37 PM Subject: Re: [boost] Ranged type mini-library submission
On 5/16/04 11:09 AM, "christopher diggins" <cdiggins@videotron.ca> wrote: [snip]
Should those "value" types be more like "value_type" to reduce confusion on what that member is?
-- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com
The version at http://www.cdiggins.com/constrained_value.hpp is less confusing I think. Though I still use value instead of value_type, I think it is perhaps more clear from the context that value is a type as opposed to another kind of identifier. I have included the latest version below so that a copy will exist for perpetuity in the list archives. I will be posting documentation on Tuesday. #ifndef BOOST_CV_HPP #define BOOST_CV_HPP #include <boost/mpl/if.hpp> namespace boost { namespace cv { template < class constraints_policy, bool implicit_conversion_policy = true > class constrained_value { private: struct unused_struct { }; public: typedef constrained_value<constraints_policy, implicit_conversion_policy> self; typedef typename constraints_policy::value value; typedef typename mpl::if_c<implicit_conversion_policy, value, unused_struct>::type value_parameter; static constraints_policy get_constraints() { return constraints_policy(); } constrained_value() { } constrained_value(const self& x) { assign(x.get_value()); } constrained_value(value_parameter x) { assign(x); } const value get_value() const { return m; } operator value() { return m; } self& operator=(const self& x) { assign(x.get_value()); return *this; } self& operator=(value_parameter x) { assign(x); return *this; } void assign(unused_struct x) { } void assign(value_parameter x) { constraints_policy::assign(x, m); } private: value m; }; }; }; #endif // BOOST_CV_HPP Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

From: christopher diggins <cdiggins@videotron.ca>
template < class constraints_policy,
^^^^^^^^^^^^^^^^^^ I think the usual naming convention would make that "Constraints" or something similar.
bool implicit_conversion_policy = true
^^^^^^^^^^^^^^^^^^^^^^^^^^ ditto: "ImplicitConversion"
> class constrained_value { private: struct unused_struct { };
Why the "_struct" suffix? Wouldn't "unused" suffice?
public: typedef constrained_value<constraints_policy, implicit_conversion_policy> self; typedef typename constraints_policy::value value; typedef typename mpl::if_c<implicit_conversion_policy, value, unused_struct>::type value_parameter;
typedef Constraints constraints_policy; typedef ImplicitConversion conversion_policy;
static constraints_policy get_constraints() { return constraints_policy(); } constrained_value() { } constrained_value(const self& x) { assign(x.get_value()); } constrained_value(value_parameter x) { assign(x); }
What if the type is not a built-in? That is, what if copying is expensive? Use TypeTraits to determine whether to pass by value or by reference.
const value get_value() const { return m; } operator value() { return m; }
Why return by value? Why not const reference? Even better, use TypeTraits to determine whether to return by value or by reference.
self& operator=(const self& x) { assign(x.get_value()); return *this; } self& operator=(value_parameter x) { assign(x); return *this; }
Use TypeTraits here, too.
void assign(unused_struct x) { } void assign(value_parameter x) { constraints_policy::assign(x, m); }
And here. Also, it you've shown the arguments in the reverse order from what I'd expect. The assignment operator puts the destination on the left, so I'd expect m on the left.
private: value m; };
-- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Rob Stewart" <stewart@sig.com> Greetings Rob, my apologies for being hotheaded earlier. To: <boost@lists.boost.org> Cc: <boost@lists.boost.org> Sent: Monday, May 24, 2004 5:29 PM Subject: Re: [boost] Ranged type mini-library submission
From: christopher diggins <cdiggins@videotron.ca>
template < class constraints_policy,
^^^^^^^^^^^^^^^^^^ I think the usual naming convention would make that "Constraints" or something similar.
I prefer the _policy extension as I feel it adds to the documentation and has no penalty to the user is never required to be typed. But I am open to the possibility of changing it if there are strong feelings one way or another.
bool implicit_conversion_policy = true
^^^^^^^^^^^^^^^^^^^^^^^^^^ ditto: "ImplicitConversion"
> class constrained_value { private: struct unused_struct { };
Why the "_struct" suffix? Wouldn't "unused" suffice?
Just trying to be as clear as possible. I do have a tendency to be overly verbose, so I would appreciate hearing how strongly you or others feel about that.
public: typedef constrained_value<constraints_policy, implicit_conversion_policy> self; typedef typename constraints_policy::value value; typedef typename mpl::if_c<implicit_conversion_policy, value, unused_struct>::type value_parameter;
typedef Constraints constraints_policy; typedef ImplicitConversion conversion_policy;
static constraints_policy get_constraints() { return constraints_policy(); } constrained_value() { } constrained_value(const self& x) { assign(x.get_value()); } constrained_value(value_parameter x) { assign(x); }
What if the type is not a built-in? That is, what if copying is expensive?
I did not anticipate this secnario. I imagined the type only used with small value types. This is somewhat implied by the name constrained_value. This is perhaps an oversight on my part. Would you be able to give a concrete example of a type with more expensive copy semantics which would be an appropriate contender? I am not being argumentitive, but simply cautious.
Use TypeTraits to determine whether to pass by value or by reference.
How specifically would be the best way to accomplish that? I am not sufficiently familiar with the technique of using TypeTraits in this manner.
const value get_value() const { return m; } operator value() { return m; }
Why return by value? Why not const reference? Even better, use TypeTraits to determine whether to return by value or by reference.
You are correct that I should be at least using const reference at this point. I have just made the changes to const references where appropriate. If I can envision an appropriate scenario for using TypeTraits that justifies the increased complexity then I could be easily swayed on this point.
self& operator=(const self& x) { assign(x.get_value()); return *this; } self& operator=(value_parameter x) { assign(x); return *this; }
Use TypeTraits here, too.
void assign(unused_struct x) { } void assign(value_parameter x) { constraints_policy::assign(x,
m); }
And here.
Also, it you've shown the arguments in the reverse order from what I'd expect. The assignment operator puts the destination on the left, so I'd expect m on the left.
Thank you for pointing that convention out to me.
private: value m; };
Thank you very much for the helpful feedback and suggestions. And again my apologies for having been belligerent before. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

On Tue, May 25, 2004 at 11:24:38PM -0400, christopher diggins wrote:
From: "Rob Stewart" <stewart@sig.com>
What if the type is not a built-in? That is, what if copying is expensive?
I did not anticipate this secnario. I imagined the type only used with small value types. This is somewhat implied by the name constrained_value. This is perhaps an oversight on my part. Would you be able to give a concrete example of a type with more expensive copy semantics which would be an appropriate contender? I am not being argumentitive, but simply cautious.
If you write data onto smartcards, the card OS sometimes imposes very specific restrictions. I once wrote an application that personalized smartcards with an RSA key-pair. The OS could use only exactly 1024 bit RSA moduli - an 1023 bit modulus was rejected. I stated this restriction in the documentation of my wrapper around the low level card terminal interface and threw an exception if the precondition was not met. (An assert was not acceptable in this particular case.) But it would have been nice if already the interface had made it obvious that only bigints with 1024 bit constitute valid input. Something along the lines of constrained_value<bigint_length_policy<1024, 1024> > where the constraints_policy is // please ignore any syntax errors template<unsigned min_length, unsigned max_length> class bigint_length_policy { public: typedef my_bigint_type value; void assign(value& lhs, value const& rhs) { if(min_length <= rhs.bitlength() && rhs.bitlength() <= max_length) { lhs = rhs; } else { throw appropriate_exception(); } } }; Of course, the efficiency of the call by value would have been no issue in my application because the time needed for transferring the data onto the smartcard probably dominates the unnecessary copy of a 1024 bit bigint on any PC or workstation not taken from the museum. But one can imagine similar situations where the overhead may be significant. What, e.g., if constrained_value was also used in the computationally expensive key generation?
Use TypeTraits to determine whether to pass by value or by reference.
How specifically would be the best way to accomplish that? I am not sufficiently familiar with the technique of using TypeTraits in this manner.
How about call_traits<T>::param_type from boost/call_traits.hpp? I had no need for this trait myself yet, whence I don't know about potential drawbacks, though. Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
I'm starting to think that Pavel is correct about the orthogonal policies.
I agree with that as an ideal, but practicalities often intervene.
Maybe we need this to be something like:
template< typename ConstraintPolicy, typename ErrorPolicy=default_error_policy, typename ImplicitConversionPolicy=allow_implicit_conversion, typename CheckingPolicy=checking_on> class constrained_value {
The downside I see here is that errors get much uglier.
That is a problem, but so too is the increasing pain of specifying a desireable combination of policies. What about using a single policy argument with everything combined? That means you can use a single class (template) or use a class template that permits specifying various pieces -- not unlike shown above -- into one class that can be the constrained_value parameter. The advantage of this approach is that it gives the policy authors greater flexibility. They can write monolithic policy classes, if desireable. They can assemble a class template that gives select configurability or one that makes it possible to supply each policy independently as you've shown. As part of the library, you could even supply the latter class template, so the library would support both extremes out of the box. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Rob Stewart" <stewart@sig.com> [snip]
That is a problem, but so too is the increasing pain of specifying a desireable combination of policies. What about using a single policy argument with everything combined? That means you can use a single class (template) or use a class template that permits specifying various pieces -- not unlike shown above -- into one class that can be the constrained_value parameter.
The advantage of this approach is that it gives the policy authors greater flexibility. They can write monolithic policy classes, if desireable. They can assemble a class template that gives select configurability or one that makes it possible to supply each policy independently as you've shown. As part of the library, you could even supply the latter class template, so the library would support both extremes out of the box.
I agree. I just posted a latest version at http://www.cdiggins.com/constrained_value.hpp which has only has two policies passed to a constrained_value type, a constraints_policy and an implicit_conversion flag. This flag I believe is best left out of the constraints_policy but I could be convinced otherwise. There is now a small demonstration program at http://www.cdiggins.com/cv_test.hpp which has some example policies. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com

christopher diggins wrote:
----- Original Message ----- From: "Rob Stewart" <stewart@sig.com> [snip]
That is a problem, but so too is the increasing pain of specifying a desireable combination of policies. What about using a single policy argument with everything combined? That means you can use a single class (template) or use a class template that permits specifying various pieces -- not unlike shown above -- into one class that can be the constrained_value parameter.
The advantage of this approach is that it gives the policy authors greater flexibility. They can write monolithic policy classes, if desireable. They can assemble a class template that gives select configurability or one that makes it possible to supply each policy independently as you've shown. As part of the library, you could even supply the latter class template, so the library would support both extremes out of the box.
I agree. I just posted a latest version at http://www.cdiggins.com/constrained_value.hpp which has only has two policies passed to a constrained_value type, a constraints_policy and an implicit_conversion flag. This flag I believe is best left out of the constraints_policy but I could be convinced otherwise.
There is now a small demonstration program at http://www.cdiggins.com/cv_test.hpp which has some example policies.
Some quick notes: -- The default constructor of constrained_value initializes the member "m" by calling the min() function, which isn't present. -- The test program is at http://www.cdiggins.com/cv_test.cpp. -- In the test program, throwing_invalid_policy should throw exception(), not exception, and allowing exception to default to void won't compile (can't throw void). -- throwing_invalid_range just uses "throw;", but doesn't appear to be called from inside a catch handler. Aside from that, it's looking pretty interesting. Bob

----- Original Message ----- From: "Robert Bell" <belvis@imageworks.com> To: <boost@lists.boost.org> Sent: Monday, May 17, 2004 2:54 PM Subject: [boost] Re: Ranged type mini-library submission [snip]
Some quick notes:
-- The default constructor of constrained_value initializes the member "m" by calling the min() function, which isn't present.
-- The test program is at http://www.cdiggins.com/cv_test.cpp.
-- In the test program, throwing_invalid_policy should throw exception(), not exception, and allowing exception to default to void won't compile (can't throw void).
-- throwing_invalid_range just uses "throw;", but doesn't appear to be called from inside a catch handler.
Aside from that, it's looking pretty interesting.
I have made these changes, thanks. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
participants (8)
-
Christoph Ludwig
-
christopher diggins
-
Daryle Walker
-
Jeff Garland
-
Pavol Droba
-
Rob Stewart
-
Robert Bell
-
Victor A. Wagner Jr.