[constrained_value] Constrained Value review results

Greetings, Substituting for Jeff Garland, I am pleased to present the results from the constrained_value review. The library is available at http://rk.dl.pl/f/constrained_value.zip The documentation is at http://rk.dl.pl/r/constrained_value Enjoy! Gordon 1. History The idea for a constrained value library goes back to at least 2004; Christopher Diggins proposed a mini-library at that time. In 2007 Joe Gottman suggested that Jeff Garland's constrained_value.hpp in date_time could be a top-level library. Concurrently, Robert Kawulak (henceforth RK) was working on his own library for the purpose, which he also started in 2004, unaware of the others. RK announced his library on November 11, 2007. Discussion continued into 2008; on June 19, RK announced his library was ready for review and it was put in the queue. The review began on December 1 2008 and continued until around December 15 (with some trailing discussion of the definition of invariant and why exceptions should not be used to check invariants). Gordon Woodhull reviewed the thread's 260 messages in the summer of 2010 and produced this report, dividing the issues raised between those where there was consensus on a change, those where no resolution was found, and those where the author and requesters (mostly) agreed that no change was needed. 2. Votes Eight people voted for acceptance of the library; there were no "no" votes. However, many people stated conditions on acceptance. Thanks to Chris (indy271828@sympatico.ca), Vicente Botet, Zach Laine, John Maddock, Thorsten Ottosen, Stjepan Rajko, Daryle Walker, and Gordon Woodhull for providing reviews. (In addition, Paul Bristow provided a review which looks like a yes but does not explicitly say so.) Thanks also to David Abrahams, Kim Barrett, Neal Becker, Paul Bristow, Edward Diener, Jeff Flinn, Joe Gottman, Mathias Guanard, Mika Heiskanen, Giovanni Pierro Deretta, Thomas Klimpel, Michael Marcin, OvermindDL1, John Phillips, raindog, Ravi (lists_ravi@lavabit.com), Johan Råde, Sebastian Redl, Peter Simons, Steven Watanabe, Utku Yaman, and Deane Yang for participating in a very active discussion. 3. Issues to be Addressed Floating point By far the most contentious issue in the review was the statement in the library documentation that floating point is not supported, and a few reviewers made fixing this a condition on acceptance. The issue is that the x87 math instructions (which are the default for 32-bit Intel compiles) utilize 80-bit registers which are then rounded down to 64 bits when a double value is written to memory. This can cause two values which were not equal to become equal later, with fairly unpredictable behavior depending on optimization and what code intervenes between calculating a value and comparing it. One solution is simply not to use the x87 math instructions by enabling the SSE2 math instructions instead. However, users may want the extra precision, and there is no way for a library to control this option. A few reviewers confused this issue with the frequent need for fuzzy comparison with epsilon; it was shown that the bug can still appear with epsilon-based comparisons. Jeff Garland points out that the Boost Numeric Interval library, http://www.boost.org/doc/libs/1_42_0/libs/numeric/interval/doc/interval.htm has also dealt with the x87 and NaN problems. It uses the round-trip-to-memory approach for x87. There is potential to create constraints for constrained_value using numeric::interval, and perhaps any other fixes for floating point belong in that library. Many solutions were proposed; after debate there were four left standing: * Force the new value to be written to memory Kim Barrett suggested the following function, noting that it should not force a memory write unless the value is in a register. inline double exact(double const& x) { return *const_cast<double const volatile*>(&x); } Gordon Woodhull has tested this against example provided by Thomas Klimpel in a message titled "floating point FUD" of January 23, 2010 (http://article.gmane.org/gmane.comp.lib.boost.devel/198817) and it does work. However, many people objected to this solution because of efficiency concerns: it requires a round-trip to memory (or at least to cache) for every assignment. * Only allow >= or <= for floating point types, and make sure the bounds are truncated 80- to 64-bit truncation can cause two values to become equal, but if one of them is already truncated, it cannot cause them to swap order. Since it is likely that the value will be changed much more frequently than the bound, it would suffice to apply truncation just to the bounds when they are set, e.g. with the exact() function above. However it does not seem that this solution can work if the bounds are dynamically calculated; the library supports bounds being returned by an inlined function. Johan Råde also suggested that it might be possible to implement < and > in terms of <= and >= and the std::nextafter function. * Force the processor to use 64-bit precision Johan Råde mentions a floating point control register which could be used in http://article.gmane.org/gmane.comp.lib.boost.devel/183760 There were also mentions of possible assembly code solutions, but none were provided and this was generally unpopular because it requires someone very knowledgeable to maintain it. John Phillips argued that reducing the precision will "lose significance faster than expected". * Another interesting solution was suggested by Stjepan Rajko: that the test might not be the same as the invariant. This is what testing with epsilon would guarantee. If the value passes the test it is guaranteed to satisfy the invariant, but only the test and not the invariant is in code. So some values might be rejected which are okay, but no bad value is accepted. RK felt that any floating point solution should be implemented separately from constrained_value, because he does not have the expertise. But he should be willing to document the scope of the problem better, including the SSE2 compiler flags that avoid the problem altogether. The first solution (truncation of the value) does not seem to require any changes to the library. Truncating the bounds might require some extra customization points. NaN Another problem with floating point is NaN, which compares false with everything. It might be okay if the bounds inclusion test always returned false. But the closed range is implemented as !(x < lower) && !(upper < x). Stjepan Rajko suggested that it should always be compare(lower, x) && compare(x, upper) where compare is < for excluded bounds and <= for included. It seems like this solution would work well for floats but not necessarily for user-defined types, which might only define operator<(). Substitutability with the underlying type A few people requested the ability to set a compiler flag in order to substitute the constrained_value with the underlying type. This is not exactly possible, unless the user is willing to explicitly extract the value using static_cast<T>(cv). The library does provide unconstrained<> which in most cases optimizes away, but the interface is not perfectly compatible with the underlying type. Constraints not copied when operators used The use of operators invokes implicit conversion to the underlying type, which means that in a statement like constrained_value x(10, constraint(...)), y(-x); y ends up with uninitialized constraints. Steven Watanabe suggested that the operators could be overloaded, but RK argued that the behavior would be application-specific: "For some applications returning a constrained value would be OK (but again there is the problem that the constraint may reject the modified value) while for others it's better to return the underlying type." Constrained strings Jeff Garland offered that he has written constrained_string classes for allowing values from a set of strings, and for validation against a regex. RK said he might add a constraint type which validates against set<T>, and affirmed that a regex validator would be nice too. Bounding on only one side Utku Yaman and others requested a way to bound integers on only one side. RK noted that you could set one of the bounds to the maximum or minimum possible integer, but this is verbose. Default arguments would be confusing, and RK thought maybe he would supply lower_saturating_int and upper_saturating_int. Note that there is a more general problem, especially if floating point is allowed. (Also consider e.g. fixed point, rational.) Recoverable error policy - error policy changing the value There were some objections to the error policy taking three parameters - the new value, the member value, and the constraint. Does it really need to change the member value? Yes, RK explained, because this is a recoverable error policy. Vicente Botet asked that the concept be called RecoverableErrorPolicy. Serialization Neal Becker requested support for serialization. RK agreed this is worth looking into and pointed out a couple of difficulties. One, a way to not serialize empty (or static) policies is needed. Two, non-default constructible types such as odd_number might require use of load_construct_data() / save_construct_data() instead of serialize(). Rename bounded_int This class name does not convey the fact that the bounds are specified at compile time. Neal Becker suggested compile_time_bounded or static_bounded. RK says the first name is too long, and the second might imply that the bounds are static members (which is also a legitimate use case). sizeof static constrained types == sizeof underlying type Assuming that the empty base class optimization is being applied correctly, which seems to be the case, if the constraint and the error policy are empty, the size of the constrained value should be the same as the size of the underlying type. However, this was not the case on all platforms, at least at the time of the review. The library should include sizeof tests in its test suite so that potential users know if there is unexpected overhead on their platform. Specify static bounds as open<0>, closed<100> for bounded<> and bounded_int<> Requested by Vicente Botet. If possible, this would reduce the number of template arguments and would be more clear than the current bounds exclusion boolean parameters. Some default constructions may throw If zero does not satisfy the constraint, then a default-constructed constrained value may throw an exception. (There are other examples, like non-empty string.) Many reviewers requested a means to provide a default value, which can be done by wrapping the underlying type, but RK felt a default value class was out of scope. At the very least this should be documented and probably an example given. Examples Vicente Botet requested: * an example showing how to create a constrained class by derivation and/or containment which adds/removes methods from the constrained value interface * a date example where changing the month affects the bounds for the day. * example of static bounding on only one side * example of bounds calculated at runtime by a function ("runtime dynamic bounding") Others: * example of constraints with static members - allows shared mutable constraints with no overhead per instance. Tests! Many reviewers were offended that there were no tests in the review version. RK said he would write some. Documentation * document the concepts and provide tests with concept archetypes. It turns out that these are documented briefly in the doxygen documentation of constrained<> at http://tinyurl.com/39v8o6r, but many reviewers were expecting a section in the main document. * Stjepan Rajko pointed out that the constraint can't depend on mutable members of the underlying type, and wondered if there were other implicit requirements, such as the way copy construction or swapping works. He requested these be documented. * Gordon Woodhull suggests a section on space efficiency and which configurations should allow the size to be optimized to the same size as the underlying type, and spelling out in each example what the cost in space is. * Thorsten Ottosen requested benchmarks of non-checking unconstrained against just using the underlying type. RK offered that he had looked at the generated assembly on some platforms. 4. Unresolved debates Error policy is allowed to change constraint Vicente Botet objected to the "bounded object with memory" example, which tracks extremal values by setting the bounds to include any new values. And Thorsten Ottosen objected to the inefficiency of change_constraint using construct-and-swap: it's not necessary to swap the constraint unless it might be changed by the error policy. This seems to be an example of a monitored value, which RK does not want to write himself, so does it belong in this library? RK argued that it does no harm, so why not allow? Double-checking and disabling assertions A number of people were concerned with the inefficiency of first checking the constraint, and then also asserting that the constraint is satisfied after the assignment has happened or the error handler has been called. But RK argued that it was necessary to check the invariant to make sure that the assignment operator and the error handler are doing their job. Besides, it is possible to disable the asserts with either BOOST_DISABLE_ASSERTS or NDEBUG. There was some discussion of adding an assert policy or a specific macro (with no clear conclusion). Disabling checks There is unconstrained, which offers a way to replace one constrained type with an unconstrained type, but Chris (indy271828@sympatico.ca) requested a way to disable all checks with a single macro. It might not be good enough to use a single error policy and select between throwing version and an assign-anyway version, because the compiler won't always optimize this away. More members, less free functions Thorsten Ottosen thought that any functions which change the state of the object should be members, not free functions. In particular, change_constraint might be less efficient than possible because the construct-and-swap requires copying the constraint. This does seem to be partly an ideological debate. Specific classes instead of a general super-template Vicente Botet requested that the interface use specific classes instead of typedefs: currently many of the specializations, like bounded<>, are metafunctions that apply some parameters to the generic constrained_value and return a new type, and then the specific operations are free functions. Instead these could be full classes with member functions. RK argued that this would result in unnecessary duplication. Way to disable the arithmetic operators Vicente Botet requested a solution in code or in documentation for users who don't want the arithmetic operators defined. 5. Ideas not requiring any action Monitored Values Stjepan Rajko suggested (and Vicente Botet expanded on the idea) that constrained value is really a special case of a more general "monitored value" class, in which a monitor policy decides how to handle any assignment. So constrained value would be a monitored value where the monitor policy checks a constraint, possibly calls an error policy, and then asserts the constraint. RK did not want to implement this and resisted suggestions to allow the assertion to be disabled in order to allow this use case, because without an invariant, it's not really a constrained value. But he suggested that monitored value could be implemented by someone else and constrained value could be re-implemented in terms of it. "Monitored value" might not be the best name for the general class, because "monitor" suggests something passive, rather than something which controls the outcome of assignment. A way to run a function on a constrained value Stjepan Rajko requested a way to make a copy of the value, run a function on it, and then reassign back, preferring the syntax call_using_copy(f, x) to x = f(x). But he notes this could be written as a free function. Multiple ranges Edward Diener requested a way to supply multiple ranges, but agreed that the syntax would be unattractive. Assertions instead of exceptions Thorsten Ottosen requested a way to have only assertions and no exceptions, and RK pointed out that this can be done either by specifying an error policy which asserts, or even with an assign-anyway error policy, which leaves the invariant checking in place. Exclude bounds parameter Vicente Botet found it confusing that bounded_int takes false to mean include bounds and true to mean exclude the bounds. RK explained that this is an artifact of the way within_bounds is templated on a type which can be either a compile-time or a runtime value, e.g. mpl::true_ or bool; this technique means there can be no default argument to the constructor and thus the more common option must be false, the default constructed value of bool. Constraints between several variables. Vicente Botet suggested a sort of constrained_tuple where if you set one field it would affect the constraints for the other fields. E.g. a date object where the month and year would affect the valid range for the day. With the current interface you'd have to set the whole date at once. Constrained values as sets of instances Exploring the problem domain, Vicente Botet suggested another possible implementation of constrained value where the constrained value type keeps track of which instances satisfy the constraint. This class would offer a split operation which moves any instances which satisfy a more specific constraint into the new set. Changing the constraint would similarly return the set of instances which are now excluded.

On Sat, Sep 11, 2010 at 3:47 PM, Gordon Woodhull <gordon@woodhull.com> wrote:
Substituting for Jeff Garland, I am pleased to present the results from the constrained_value review.
Gordon, Many thanks for taking this on and for the thorough report. However, a critical piece of information seems to be missing (or buried so I can't find it): is the library accepted? Conditionally or unconditionally? Thanks, -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sep 11, 2010, at 8:57 PM, Dave Abrahams wrote:
Many thanks for taking this on and for the thorough report. However, a critical piece of information seems to be missing (or buried so I can't find it): is the library accepted? Conditionally or unconditionally?
Sorry I didn't make this clear! Yes, the votes were unanimous in favor. There were conditions on acceptance from some reviewers. In particular, 3-4 reviewers made floating point support a condition on acceptance - for many of us that is exactly what we'd want to use the library for most. I think after debate everyone accepted that the solution didn't need to come from this library, but that Robert would have to make changes for floating point support, if needed, and to change the documentation to make it less inflammatory. The lack of tests was the second biggest objection - the library probably should not have been reviewed without them. Of course Robert has promised over and over to include them before the library is released. Vicente Botet's acceptance was perhaps the most conditional, and unique, so I'll quote him:
I would like to say that it should be accepted IF some of the following suggestions are taken in account, as * separation between constrained and constraint_adaptor * use of classes instead of typedefs and removal of the free functions * specialization of the operators with a possible parameter with_arithmetic_operators. * adding a default value template parameter to the value type. * reduction of the number of parameters of the class bounded (posible use of open<> and close<>) * reduction of the number of parameters of the class bounded_int (posible use of open_c<> and close_c<>)
Thorsten Ottosen's conditions on acceptance were also numerous, but I believe they were all resolved in debate. Thorsten, please correct me if I am wrong. All of the items in section 3 must be addressed at least in documentation. In some cases, they can only be addressed that way ("Substitutability with the underlying type", "Constraints not copied when operators used"). To my memory, no one asked for a second review, so it is my judgment that once Robert has addressed section 3 the library can be released. Robert, please post any objections. Cheers, and congratulations, Gordon

On Sep 12, 2010, at 1:38 AM, Gordon Woodhull <gordon@woodhull.com> wrote:
There were conditions on acceptance from some reviewers.
In case I am still being unclear, this is conditional acceptance, the conditions being listed in section 3. (Yes, I do have problems with assuming authority. ;-) Gordon

Den 12-09-2010 07:38, Gordon Woodhull skrev:
Thorsten Ottosen's conditions on acceptance were also numerous, but I believe they were all resolved in debate. Thorsten, please correct me if I am wrong.
As for the member vs. non-members, then I have no strong preference, but remain convinced that changing state of objects with a non-trivial invariant is best done by a member function. As for the floating point problems, then I have not read any subsequent threads on this. My recolllection was that we did solve the problem during the discussion (was it using <= and >= exclulsively and always trucating the bound to 64 bits?). -Thorsten

Hi Thorsten,
As for the member vs. non-members, then I have no strong preference, but remain convinced that changing state of objects with a non-trivial invariant is best done by a member function.
I happen to agree with you here, but this seemed to be a debate which was going nowhere, and eventually these design decisions are up to the discretion of the author. There wasn't a huge efficiency gain to making change_constraint a method, because it would still have to construct-and-swap as long as the constraint could be changed. Perhaps with a finer-grained abstraction - but I'm digressing.
As for the floating point problems, then I have not read any subsequent threads on this. My recollection was that we did solve the problem during the discussion (was it using <= and >= exclusively and always truncating the bound to 64 bits?).
There's an interesting thread on floating point FUD which I linked to. Yes, I think that was the agreed solution. Efficiency be damned for an obsolescent architecture. It is interesting to see that numeric::interval came to the same conclusion about round-tripping the bounds to memory. Their bounds are also closed, included. Those guys could have set us straight a lot quicker, but it's nice to see convergent evolution. Cheers, and thanks, Gordon

Den 14-09-2010 09:41, Gordon Woodhull skrev:
As for the floating point problems, then I have not read any subsequent threads on this. My recollection was that we did solve the problem during the discussion (was it using<= and>= exclusively and always truncating the bound to 64 bits?).
There's an interesting thread on floating point FUD which I linked to.
Yes, I think that was the agreed solution. Efficiency be damned for an obsolescent architecture. It is interesting to see that numeric::interval came to the same conclusion about round-tripping the bounds to memory. Their bounds are also closed, included. Those guys could have set us straight a lot quicker, but it's nice to see convergent evolution.
For many bounds we don't have to worry about round trips to memory. We have people producing 64bit math constants which can just be used directly, and which would satisfy most use cases IMO. -Thorsten

From: Gordon Woodhull All of the items in section 3 must be addressed at least in documentation. In some cases, they can only be addressed that way ("Substitutability with the underlying type", "Constraints not copied when operators used").
To my memory, no one asked for a second review, so it is my judgment that once Robert has addressed section 3 the library can be released. Robert, please post any objections.
You want to say literally all? I mean, some of the points were rather suggestions or minor requests (at least I felt so) or had no clear conclusion, e.g. "seralization" or "rename bounded_int", to name a few. For some of them I don't see how I could address them in documentation or why should they be crucial for final acceptance (don't get me wrong - I'm open for suggestions, but for instance if I were to add all the examples suggested by people to the docs, it would become too bloated and out of topic. A software maintainer can't do everything to please anybody but has to choose which requests to implement and which not to). To conclude - I don't feel section 3 contains only major issues, so should all of them be crucial for acceptance? Best regards, Robert

Hi Robert,
You want to say literally all? I mean, some of the points were rather suggestions or minor requests (at least I felt so) or had no clear conclusion, e.g. "serialization" or "rename bounded_int", to name a few.
I meant to include in this section only changes that you agreed to. If there are items which you now disagree with, or which still require substantial debate or effort, then sure, they should not be conditions on acceptance. Not everything which should be done has to be done before release. There will be further maintenance afterward. However, I don't think it's just the "major" issues which should be addressed. There is also value in solidifying the interface before release. I don't think it will be too onerous to implement most of these - see below.
For some of them I don't see how I could address them in documentation or why should they be crucial for final acceptance (don't get me wrong - I'm open for suggestions, but for instance if I were to add all the examples suggested by people to the docs, it would become too bloated and out of topic.
Not all examples have to go into the documentation. People will also look in the examples directory for hints how to do something.
A software maintainer can't do everything to please anybody but has to choose which requests to implement and which not to).
Which is why I tried to put only the items on which you agreed in this section.
To conclude - I don't feel section 3 contains only major issues, so should all of them be crucial for acceptance?
So let's walk through the items and decide which need to be addressed before release.
Floating point
Here's it's possible to specify a constraint outside of the library, and it seems that for x87 it is going to need to make sure the bounds have made a round-trip to memory (unless there is a more efficient trick). So there is no modification needed here, unless a float-specific API will be provided. Hopefully this can happen quickly, maybe even before release, but it is not your responsibility.
NaN
Likewise.
Substitutability with the underlying type
Document why this is not possible, drawing from your very cogent explanations on the list.
Constraints not copied when operators used
Same.
Constrained strings
It shouldn't be difficult to provide an example of validation against a set of strings, and perhaps a regex example. To reduce effort, these could be kept as examples until the classes mature enough to be included in the library proper.
Bounding on only one side
If this requires interface changes, it would be better to do this before release. If it just requires more classes and no changes to those existing, then it could wait. This seems like a very useful feature; on the other hand it's not part of the essential design of the library, really just more predicates and convenience classes. I'd encourage you to implement it soon to maximize your audience. A rough draft could go into the examples.
Recoverable error policy - error policy changing the value
The action item here is to clearly call it a "recoverable error policy" to explain why it can change the member value. There was also some interesting design discussion here, but not requiring action.
Serialization
Probably not required for release, but pretty important.
Neal Becker requested support for serialization. RK agreed this is worth looking into and pointed out a couple of difficulties. One, a way to not serialize empty (or static) policies is needed. Two, non-default constructible types such as odd_number might require use of load_construct_data() / save_construct_data() instead of serialize().
These don't seem to be insuperable difficulties, but perhaps they will require more time to resolve.
Rename bounded_int
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time. I think you agreed that a name change is needed, and if so, it should go in before release. I know that naming classes can be frustrating, but just because you don't like the names compile_time_bounded or static_bounded does not mean that change isn't necessary.
test: sizeof static constrained types == sizeof underlying type
Essential! (and not just because it's one of mine!)
Specify static bounds as open<0>, closed<100> for bounded<> and bounded_int<>
Maybe wishful thinking on my part. You said you'd look into this. The boolean open/closed flags are definitely confusing.
Some default constructions may throw
Defaulted values are probably out of scope, but a warning in the documentation about odd_int and its ilk is a good idea.
Examples
* an example showing how to create a constrained class by derivation and/or containment which adds/removes methods from the constrained value interface
You didn't want to do this, so maybe it belongs in the unresolved debates section.
* a date example where changing the month affects the bounds for the day.
You said you'd try this. Again, it doesn't necessarily need to complicate the documentation, and it doesn't need to be perfect if it's just an example. (E.g. it could comment that it doesn't support leap years. ;-) Maybe it doesn't need to go in before release, but as Vicente pointed out, for anyone thinking about dates, this is the first thing that will come to mind.
* example of static bounding on only one side
At worst this could be an example with INT_MAX/INT_MIN. An important feature which belongs in the documentation.
* example of bounds calculated at runtime by a function ("runtime dynamic bounding")
This just seems to be a more complicated constraint which has extra data or which calls into something else that has state (like a timer). Vicente might be able to provide a simple example. Maybe not necessary for release.
* example of constraints with static members - allows shared mutable constraints with no overhead per instance.
I think may have been one of mine - not necessary for release but an interesting curiosity. Another related idea which came up outside the review was the idea of constrained_container, where the constraint is shared by all elements, but I ran into trouble with the obvious implementation using proxy constrained_values of reference type.
Tests!
Deadly essential for release. In summary, these are mostly ideas which you agreed are important, so to avoid redundant questions on the list, please document and/or provide (imperfect) examples. Yes it is some work, but IMO one purpose of the review is to show that you are willing to maintain and respond to requests. Cheers, Gordon

From: Gordon Woodhull So let's walk through the items and decide which need to be addressed before release.
Thanks for the clarification, now it looks very reasonable. :) BTW if there are people out there who were already using the library - I'd be very grateful for any comments (positive or negative ;-) on how it works in real code. Best regards, Robert

Robert Kawulak wrote:
From: Gordon Woodhull So let's walk through the items and decide which need to be addressed before release.
Thanks for the clarification, now it looks very reasonable. :)
BTW if there are people out there who were already using the library - I'd be very grateful for any comments (positive or negative ;-) on how it works in real code.
Best regards, Robert
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
I'm currently using it as the basis of my fixed point work. I'm not actively developing this, so nothing comes to mind. Everything is working satisfactorily.

Hello All, As Gordon Woodhull has suggested, it'd be nice to try finding a better name for bounded_int:
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time.
And from private correspondence:
As Thorsten mentioned, it might be helpful to brainstorm/vote on the list for a better name for bounded_int. My favorite at this point is static_bounded, since the use of a class static variable for bounds is probably rare. But you could probably do better.
The template in a simplified form looks like this: template<typename ValueType, ValueType LowerBound, ValueType UpperBound> struct bounded_int { ... } Its characteristics are that the underlying value type is the same as the bounds type and the bounds are specified as compile time constants. According to the C++ Standard, type of the constants may be: - integral/enumeration, - pointer/reference to object/function, - pointer to member. Of the types, the most likely use case is integral, whence the name bounded_int (as a shortcut for "bounded integral", not necessarily "bounded integer"). This name does not express all the possible use cases, but it's hard to find a terse form of bounded_by_compile_time_constants. Somehow I don't like static_bounded because it may suggest that the underlying value or the bounds are static objects (in the meaning "global"); fixed_bounded or compile_time_bounded sounds no better to me. So, as I'm having difficulty with finding a good name, any ideas and opinions are appreciated. :) Best regards, Robert

Robert Kawulak wrote:
As Gordon Woodhull has suggested, it'd be nice to try finding a better name for bounded_int:
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time.
A reasonable complaint, especially as there may be a runtime bounded integral type. "bounded_int" could apply to either, so probably should be applied to neither.
And from private correspondence:
As Thorsten mentioned, it might be helpful to brainstorm/vote on the list for a better name for bounded_int. My favorite at this point is static_bounded, since the use of a class static variable for bounds is probably rare. But you could probably do better.
"static" in this case is akin to that in BOOST_STATIC_ASSERT, which means compile time. My preference is to use "CT" for that (because its an abbreviation for "compile time"), though it is very terse and could mean other things in other contexts.
The template in a simplified form looks like this:
template<typename ValueType, ValueType LowerBound, ValueType UpperBound> struct bounded_int { ... }
Its characteristics are that the underlying value type is the same as the bounds type and the bounds are specified as compile time constants. According to the C++ Standard, type of the constants may be: - integral/enumeration, - pointer/reference to object/function, - pointer to member. Of the types, the most likely use case is integral, whence the name bounded_int (as a shortcut for "bounded integral", not necessarily "bounded integer"). This name does not express all the possible use cases, but it's hard to find a terse form of bounded_by_compile_time_constants. Somehow I don't like static_bounded because it may suggest that the underlying value or the bounds are static objects (in the meaning "global"); fixed_bounded or compile_time_bounded sounds no better to me.
"compile_time_bounded_int" is long, but clearly describes the class template. (I didn't use "integral" because that has at least one other plausible meaning and cannot be disambiguated without context.) You could also shorten or substitute words. For example, instead of "compile_time," use "ct," "constant," or "const," and instead of "bounded," use "bound," "bounds," or "constrained." Thus, I can offer these names: compile_time_bounded_int compile_time_bound_int compile_time_constrained_int ct_bounded_int ct_bound_int ct_constrained_int constant_bounded_int constant_bounds_int constant_bound_int constant_constrained_int const_bounded_int const_bounds_int const_bound_int const_constrained_int The "const_" prefix is suggestive of "const_iterator" and the like, so may not be a good idea, but I think the "constant_" prefix is sufficiently different to work. "const" or "constant" followed by "constrained" is a bit hard to pronounce.
From among these, my vote would be for "ct_bound_int" or "constant_bounds_int" and being short and clear.
_____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

From: Stewart, Robert My preference is to use "CT" for that (because its an abbreviation for "compile time"), though it is very terse and could mean other things in other contexts.
"ct" is indeed cryptic, but I think it won't be easily mistaken for something else (like "int" in "bounded_int" might be) and once one gets to know it stands for "compile time" the names become quite clear: bounded<int> // bounds specified at runtime bounded_ct<int, 0, 10> // bounds specified as compile time constants Looks good to me. Maybe even "c" alone would suffice? bounded_c<int, 0, 10> Reminds me of boost::mpl::integral_c.
instead of "bounded," use "bound," "bounds,"
Using "bound" or "bounds" seems misleading to me. The object represented by the type is a bounded value, not value of the bounds.
or "constrained."
Constrained objects are a superset of bounded objects while we're looking for a name for a subset of bounded objects so using "constrained" does not make sense.
From among these, my vote would be for "ct_bound_int" or "constant_bounds_int" and being short and clear.
The "int" suffix is unnecessary, the whole point was to replace it with something better. ;-)
From: Christian Holmquist I think bounded_int or bounded_integral seems just fine.
bounded_integral is more precise than bounded_int, but still not exhaustive (integrals are not all possible types that can be used).
From: Thorsten Ottosen bounded_int and bounded_float is fine with me too. Since the library is called constrained_value, contrained_int and constrained_float would be fine too.
Ditto about "constrained". And why "bounded_float"? I was thinking that for floats you would just use "bounded" template.
From: Paul A. Bristow I also like the word 'static' - it implies 'fixed at compile time' to me, but I agree static has other possible implications.
How about "statically_bounded"?
So
fixed_bound is my suggestion, FWIW.
fixed_bound<int, 0, 23>::type hour;
Ditto about "bound". And "fixed_bounded" looks weird, it's as if the value was itself fixed. But maybe it's not that bad? Thanks for the replies and best regards, Robert

Hi, I was thinking that static_bounded might be more easily understood by people used to static_cast. Following that logic, runtime constrainted types would be prefixed with dynamic_ like dynamic_cast. My 2 cents. On Thu, Oct 7, 2010 at 04:28, Christian Holmquist <c.holmquist@gmail.com>wrote:
bounded<int> // bounds specified at runtime bounded_ct<int, 0, 10> // bounds specified as compile time constants
Looks good to me.
Maybe even "c" alone would suffice?
bounded_c<int, 0, 10>
Reminds me of boost::mpl::integral_c.
+1 for bounded and bounded_c.
/ Christian _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

2010/10/7 Robert Kawulak <robert.kawulak@gmail.com>
bounded<int> // bounds specified at runtime bounded_ct<int, 0, 10> // bounds specified as compile time constants
Personally, I like bounded_ct. The abbreviation CT corresponds RT (run time), which is commonly used.
Maybe even "c" alone would suffice?
In my opinion suffix _c does not suffice, because it reminds me of const. If I remember correctly, in MPL the _c suffix does mean const. Therefore I vote for _ct. Regards, Kris

Krzysztof Czainski wrote:
2010/10/7 Robert Kawulak <robert.kawulak@gmail.com>
bounded<int> // bounds specified at runtime bounded_ct<int, 0, 10> // bounds specified as compile time constants
Personally, I like bounded_ct. The abbreviation CT corresponds RT (run time), which is commonly used.
My suggestion was to make "ct" a prefix akin to "static_" in static_cast and static_assert. I do like the parallel with "rt," so I would prefer these: ct_bounded<int> rt_bounded<short> Those have the advantage of being readable in English: "compile time bounded int" and "runtime bounded short." With familiarity, I imagine that "compile time" and "runtime" would be reduced to "see tee" and "arr tee." _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

2010/10/7 Stewart, Robert <Robert.Stewart@sig.com>
My suggestion was to make "ct" a prefix akin to "static_" in static_cast and static_assert. I do like the parallel with "rt," so I would prefer these:
ct_bounded<int>
rt_bounded<short>
I second the suggestion for "ct" in favour of "static" for two reasons: it is shorter, and static has its other meaning. Those have the advantage of being readable in English: "compile time bounded
int" and "runtime bounded short." With familiarity, I imagine that "compile time" and "runtime" would be reduced to "see tee" and "arr tee."
I prefere sufexes, becaluse then the part of the name, that brings most information comes first: bounded_ct<int> x; // bounded at compile time of type int bounded<int> x; // bounded (at run time) of type int Regards Kris

2010/10/7 Stewart, Robert <Robert.Stewart@sig.com>:
instead of "bounded," use "bound," "bounds,"
Using "bound" or "bounds" seems misleading to me. The object represented by the type is a bounded value, not value of the bounds.
I was using "bound" as a verb in those cases: "ct_bound" means bound at compile time. According to reference.com, "bound" as a noun is usually in the plural, so I didn't confuse "bound" as a noun in my suggestions, though I can see how others might.
You mean "bound" as past participle of "to bind", so "ct_bound" would mean something that has been bound (i.e., "binded") at compile time? I think the operation we want to express is bounding rather than binding...
My suggestion was to make "ct" a prefix akin to "static_" in static_cast and static_assert. I do like the parallel with "rt," so I would prefer these:
ct_bounded<int> rt_bounded<short>
The former is the subset of the latter, so "rt_bounded" is not a good idea since it may represent objects with compile-time-fixed bounds as well. I think just "bounded" is the best. 2010/10/7 Krzysztof Czainski <1czajnik@gmail.com>:
I prefere sufexes, becaluse then the part of the name, that brings most information comes first:
bounded_ct<int> x; // bounded at compile time of type int bounded<int> x; // bounded (at run time) of type int
I agree with you for the same reason. Moreover, if you start typing "boun..." in an IDE, its autocomplete will show both the options, so it has a small productivity advantage too. ;-) Best regards, Robert

On Thu, Oct 7, 2010 at 6:59 AM, Robert Kawulak <robert.kawulak@gmail.com> wrote:
bounded_ct<int> x; // bounded at compile time of type int bounded<int> x; // bounded (at run time) of type int
I agree with you for the same reason. Moreover, if you start typing "boun..." in an IDE, its autocomplete will show both the options, so it has a small productivity advantage too. ;-)
Do not let this be an issue, an decent IDE should show better options then that, given the names: rt_bounded ct_bounded My IDE happily shows those both if I start typing "bou" (usually at the top of the list if I have been using them recently).

From: OvermindDL1 Do not let this be an issue, an decent IDE should show better options then that, given the names: rt_bounded ct_bounded My IDE happily shows those both if I start typing "bou" (usually at the top of the list if I have been using them recently).
OFF-TOPIC: just curious - which IDE is this? :)

On Thu, Oct 7, 2010 at 6:15 PM, Robert Kawulak <robert.kawulak@gmail.com> wrote:
From: OvermindDL1 Do not let this be an issue, an decent IDE should show better options then that, given the names: rt_bounded ct_bounded My IDE happily shows those both if I start typing "bou" (usually at the top of the list if I have been using them recently).
OFF-TOPIC: just curious - which IDE is this? :)
Visual Studio 2005 with the Visual Assist plugin[0]. Yes, I even use this in a Windows XP VM to do my linux programming (using mapped folders and callbacks), there is no equivalent linux IDE to the usefulness of Visual Assist, although once one is created then I will happily drop VA, but until then, I am addicted to it as hard as any drug. [0] http://www.wholetomato.com/

Robert Kawulak wrote:
2010/10/7 Stewart, Robert <Robert.Stewart@sig.com>:
instead of "bounded," use "bound," "bounds,"
Using "bound" or "bounds" seems misleading to me. The object represented by the type is a bounded value, not value of the bounds.
I was using "bound" as a verb in those cases: "ct_bound" means bound at compile time. According to reference.com, "bound" as a noun is usually in the plural, so I didn't confuse "bound" as a noun in my suggestions, though I can see how others might.
You mean "bound" as past participle of "to bind", so "ct_bound" would mean something that has been bound (i.e., "binded") at compile time? I think the operation we want to express is bounding rather than binding...
I see the bounds as being applied at compile time, so it is bound to the specified range at compile time, so, yes, I meant the past participle of the infinitive "to bind." That the bounds continue to apply at runtime after having been bound at compile time is not, I think, the principle distinction.
My suggestion was to make "ct" a prefix akin to "static_" in static_cast and static_assert. I do like the parallel with "rt," so I would prefer these:
ct_bounded<int> rt_bounded<short>
The former is the subset of the latter, so "rt_bounded" is not a good idea since it may represent objects with compile-time-fixed bounds as well. I think just "bounded" is the best.
Strictly speaking, runtime bounded is not a superset of compile time bounded, because one cannot choose to do either with the runtime bounded class, right? Both types apply range checking at run time, and both behave like the underlying type (insofar as possible). The differences, then, are when the bounds are applied and whether they can be changed at runtime. Considering that the former is a characteristic of the latter, the principal difference is whether the bounds can change at runtime. Thus, "bounded" is insufficient for the runtime version as that name implies both categories and does not clearly suggest the runtime variability. -1 "bounded"
2010/10/7 Krzysztof Czainski <1czajnik@gmail.com>:
I prefere sufexes, becaluse then the part of the name, that brings most information comes first:
bounded_ct<int> x; // bounded at compile time of type int bounded<int> x; // bounded (at run time) of type int
I agree with you for the same reason.
We are certainly accustomed to postfix notation for many things, so using "ct" and "rt" as suffixes won't be harmful, and the names will sort lexicographically together in many contexts with the suffix. My preference still is for the prefixes, but I don't much mind the suffixes.
Moreover, if you start typing "boun..." in an IDE, its autocomplete will show both the options, so it has a small productivity advantage too. ;-)
Not using such a facility, that bears no weight with me, but if you do, I can imagine it will carry some weight with you. However, don't get carried away by that idea since few will be typing those names particularly often, at least in normal code. The names of objects of those types will be used far more often. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Robert Kawulak wrote:
From: Stewart, Robert
Maybe even "c" alone would suffice?
bounded_c<int, 0, 10>
Reminds me of boost::mpl::integral_c.
That's exactly why I dislike it. In MPL, it refers to a compile time constant. The bounds, in this case, are compile time constants, but the value represented by bounded_c isn't.
instead of "bounded," use "bound," "bounds,"
Using "bound" or "bounds" seems misleading to me. The object represented by the type is a bounded value, not value of the bounds.
I was using "bound" as a verb in those cases: "ct_bound" means bound at compile time. According to reference.com, "bound" as a noun is usually in the plural, so I didn't confuse "bound" as a noun in my suggestions, though I can see how others might. I suggested bounds because it was in the context of a name like "ct_bounds_int" in which the bounds applied to the integral type were fixed at compile time. Since "int" is not be in the name, we can use "value" instead: ct_bounds_value. In that case, though, "bound" fits better, but seems to suggest that the value is fixed at compile time (as in MPL's "_c" suffix): ct_bound_value.
or "constrained."
Constrained objects are a superset of bounded objects while we're looking for a name for a subset of bounded objects so using "constrained" does not make sense.
OK. I was just looking back at the library name and realized "constrained" wasn't among the suggestions offered or rejected in your post, so I didn't want to miss that option.
From among these, my vote would be for "ct_bound_int" or "constant_bounds_int" and being short and clear.
The "int" suffix is unnecessary, the whole point was to replace it with something better. ;-)
I didn't understand that "int" wasn't supposed to be part of the name from your initial post.
From: Paul A. Bristow I also like the word 'static' - it implies 'fixed at compile time' to me, but I agree static has other possible implications.
How about "statically_bounded"?
That's longer, but it does work. If we can agree on "ct," it would be better because shorter. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

----- Original Message ----- From: "Robert Kawulak" <robert.kawulak@gmail.com> To: <boost@lists.boost.org> Sent: Thursday, October 07, 2010 2:45 AM Subject: Re: [boost] [constrained_value] Constrained Value review results
From: Paul A. Bristow I also like the word 'static' - it implies 'fixed at compile time' to me, but I agree static has other possible implications.
How about "statically_bounded"?
+1. But I prefer static_bounded that follows the existing static_log2, static_gcd, ... in Boost.Math. Best, Vicente

Den 07-10-2010 18:27, vicente.botet skrev:
----- Original Message ----- From: "Robert Kawulak"<robert.kawulak@gmail.com> To:<boost@lists.boost.org> Sent: Thursday, October 07, 2010 2:45 AM Subject: Re: [boost] [constrained_value] Constrained Value review results
From: Paul A. Bristow I also like the word 'static' - it implies 'fixed at compile time' to me, but I agree static has other possible implications.
How about "statically_bounded"?
+1. But I prefer static_bounded that follows the existing static_log2, static_gcd, ... in Boost.Math.
I'm not awfully happy with the names suggested so far. At the outset boost::constrained_value::bounded<int> is a good name. Now, since the bounds, /not the actualy bounding/, can be configured either at compiler-time or run-time, we need some way of saying this. What about namespaces? boost::constrained_values::run_time_bounds::bounded<int> boost::constrained_values::compile_time_bounds::bounded<int> ? Or boost::constrained_values::static_bounds::bounded<int> boost::constrained_values::dynamic_bounds::bounded<int> ? -Thorsten

2010/10/8 Stewart, Robert <Robert.Stewart@sig.com>:
You mean "bound" as past participle of "to bind", so "ct_bound" would mean something that has been bound (i.e., "binded") at compile time? I think the operation we want to express is bounding rather than binding...
I see the bounds as being applied at compile time, so it is bound to the specified range at compile time, so, yes, I meant the past participle of the infinitive "to bind." That the bounds continue to apply at runtime after having been bound at compile time is not, I think, the principle distinction.
But applying fixed bounds at compile time is not a defining characteristic of "bounded_int", it is using compile time constant expressions to specify the bounds.
ct_bounded<int> rt_bounded<short>
The former is the subset of the latter, so "rt_bounded" is not a good idea since it may represent objects with compile-time-fixed bounds as well. I think just "bounded" is the best.
Strictly speaking, runtime bounded is not a superset of compile time bounded, because one cannot choose to do either with the runtime bounded class, right? [...] Thus, "bounded" is insufficient for the runtime version as that name implies both categories and does not clearly suggest the runtime variability.
-1 "bounded"
I'm not trying to say that runtime bounded is a superset of compile time bounded, but that "bounded" is a superset of "bounded_int". You can use "bounded" with static or dynamic bounds. There are even cases when "bounded_int" cannot be used to define static bounds and you have to use "bounded" instead – these are all the cases where the bounds cannot be expressed directly using compile time constant expressions, e.g. for floats or rational numbers. See the example with rational numbers in the second part of this subsection: http://tinyurl.com/332vmf5#constrained_value.tutorial.compile_time_fixed_bou... 2010/10/8 Thorsten Ottosen <nesotto@cs.aau.dk>:
What about namespaces?
boost::constrained_values::run_time_bounds::bounded<int> boost::constrained_values::compile_time_bounds::bounded<int>
?
Or
boost::constrained_values::static_bounds::bounded<int> boost::constrained_values::dynamic_bounds::bounded<int>
?
Ditto. Best regards, Robert

Robert Kawulak wrote:
2010/10/8 Stewart, Robert <Robert.Stewart@sig.com>:
I see the bounds as being applied at compile time, so it is bound to the specified range at compile time, so, yes, I meant the past participle of the infinitive "to bind." That the bounds continue to apply at runtime after having been bound at compile time is not, I think, the principle distinction.
But applying fixed bounds at compile time is not a defining characteristic of "bounded_int", it is using compile time constant expressions to specify the bounds.
I fail to understand the distinction you wish to make. The two sound alike to me. (Also note that I never referenced your "bounded_int" in my discussion.) Let me clarify something that has just occurred to me. I've been writing strictly in the abstract about a compile time bounded type and a runtime bounded type and about names for them. I've not been making any specific references to your types as they now exist.
ct_bounded<int> rt_bounded<short>
The former is the subset of the latter, so "rt_bounded" is not a good idea since it may represent objects with compile-time-fixed bounds as well. I think just "bounded" is the best.
Here I think you're trying to map "rt_bounded" to your "bounded" and "ct_bounded" to your "bounded_int" which is restrictive. See more below.
Strictly speaking, runtime bounded is not a superset of compile time bounded, because one cannot choose to do either with the runtime bounded class, right? [...] Thus, "bounded" is insufficient for the runtime version as that name implies both categories and does not clearly suggest the runtime variability.
I'm not trying to say that runtime bounded is a superset of compile time bounded, but that "bounded" is a superset of "bounded_int".
Here's an example of where we're talking past one another. I'm discussing the word "bounded" as not being sufficient to indicate a type with runtime specified bounds.
You can use "bounded" with static or dynamic bounds.
As a reference to your class template, "bounded" does apply to both types of bounds. However, the word "bounded" is insufficient in my mind; it includes both types of bounded types. I think there should be two distinct names for the two types of bounded values.
There are even cases when "bounded_int" cannot be used to define static bounds and you have to use "bounded" instead these are all the cases where the bounds cannot be expressed directly using compile time constant expressions, e.g. for floats or rational numbers. See the example with rational numbers in the second part of this subsection: <http://tinyurl.com/332vmf5#constrained_value.tutorial.compile_time_fixed_bounds>
In which case the type cannot be compile time bound and a runtime bound type must be used. I see no problem here. Making things specific, I'd like to see your bounded class template be an implementation detail with two public types that use it to do the heavy lifting. (If you think that is insufficient for some reason, then expose all three with your current bounded class template being documented as the advanced form.)
2010/10/8 Thorsten Ottosen <nesotto@cs.aau.dk>:
What about namespaces?
boost::constrained_values::run_time_bounds::bounded<int> boost::constrained_values::compile_time_bounds::bounded<int>
?
Or
boost::constrained_values::static_bounds::bounded<int> boost::constrained_values::dynamic_bounds::bounded<int>
?
Ditto.
I dislike that idea because one must type the scope resolved name to disambiguate and seeing "bounded" in code is insufficient; one must find using directives/declarations in the context to know which type "bounded" references. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

From: Stewart, Robert Let me clarify something that has just occurred to me. I've been writing strictly in the abstract about a compile time bounded type and a runtime bounded type and about names for them. I've not been making any specific references to your types as they now exist.
OK, sounds reasonable. The thing is that the "bounded" class template is universal and equally suitable for dynamic and static bounds. The only reason for existence of "bounded_int" is to save some typing when defining bounded types that have bounds expressible as compile time constant expressions. So instead of: bounded< int, boost::mpl::integral_c<int, 0>, boost::mpl::integral_c<int, 10> > you can just say: bounded_int<int, 0, 10> So yes - the "rt_bounded"/"ct_bounded" abstraction doesn't map to "bounded"/"bounded_int" and what I'm asking for is NOT a name for bounded class with bounds that don't change, but a better name for "bounded_int".
There are even cases when "bounded_int" cannot be used to define static bounds and you have to use "bounded" instead these are all the cases where the bounds cannot be expressed directly using compile time constant expressions, e.g. for floats or rational numbers. See the example with rational numbers in the second part of this subsection: <http://tinyurl.com/332vmf5#constrained_value.tutorial.compile_time_fixed_bounds>
In which case the type cannot be compile time bound and a runtime bound type must be used. I see no problem here.
Strictly speaking it's not a runtime bound. You cannot change the value of quarter2type object. It has no storage and only expresses some fixed value by its type, just like boost::mpl::integral_c does. Here's the difference (using types from the example above): bounded<rational>::type rt_rational; change_upper_bound(rt_rational, rational(1, 3)); // OK - can change bounds at runtime bounded<rational, quarter2type, half2type>::type ct_rational; change_upper_bound(ct_rational, rational(1, 3)); // COMPILATION ERROR!
Making things specific, I'd like to see your bounded class template be an implementation detail with two public types that use it to do the heavy lifting. (If you think that is insufficient for some reason, then expose all three with your current bounded class template being documented as the advanced form.)
I see no big advantage in doing so - the hypothetical "rt_bounded" class would then serve similar purpose as "bounded_int", that is wrapping "bounded" to save a few keystrokes, but as opposed to "bounded_int" it would save them only in rare cases (for instance when you would be overriding the default error policy) - most of the time there would be no difference, because defining a type with runtime bounds is as simple as: bounded<int>::type my_runtime_bounded_int; And for cases like rationals or floats with fixed bounds you would have to use "bounded" anyway, so it cannot become an implementation detail only.
From: vicente.botet Sorr bau I dont see the difference. I consider ratio<N,D> to express a compile time constant through a type, as integral_c or integral_constant do.
Sorry, maybe I've been unclear - by "compile time constant" I mean what C++ Standard describes as constant expression. Therefore, a type is not a compile time constant in this sense. Best regards, Robert

Robert Kawulak wrote:
From: Stewart, Robert
Let me clarify something that has just occurred to me. I've been writing strictly in the abstract about a compile time bounded type and a runtime bounded type and about names for them. I've not been making any specific references to your types as they now exist.
OK, sounds reasonable. The thing is that the "bounded" class template is universal and equally suitable for dynamic and static bounds. The only reason for existence of "bounded_int" is to save some typing when defining bounded types that have bounds expressible as compile time constant expressions. So instead of:
bounded< int, boost::mpl::integral_c<int, 0>, boost::mpl::integral_c<int, 10> >
you can just say:
bounded_int<int, 0, 10>
That is certainly worthwhile.
So yes - the "rt_bounded"/"ct_bounded" abstraction doesn't map to "bounded"/"bounded_int" and what I'm asking for is NOT a name for bounded class with bounds that don't change, but a better name for "bounded_int".
To create good names does require good understanding which I clearly didn't have and I'm still fuzzy on a couple of points, I think.
There are even cases when "bounded_int" cannot be used to define static bounds and you have to use "bounded" instead these are all the cases where the bounds cannot be expressed directly using compile time constant expressions, e.g. for floats or rational numbers. See the example with rational numbers in the second part of this subsection:
<http://tinyurl.com/332vmf5#constrained_value.tutorial.compile_time_fixed_bounds>
In which case the type cannot be compile time bound and a runtime bound type must be used. I see no problem here.
Strictly speaking it's not a runtime bound. You cannot change the value of quarter2type object. It has no storage and only expresses some fixed value by its type, just like boost::mpl::integral_c does. Here's the difference (using types from the example above):
bounded<rational>::type rt_rational; change_upper_bound(rt_rational, rational(1, 3)); // OK - can change bounds at runtime
bounded<rational, quarter2type, half2type>::type ct_rational; change_upper_bound(ct_rational, rational(1, 3)); // COMPILATION ERROR!
OK, so if I have things right, there's the notion of fixed bounds that, once set, cannot be changed thereafter. How they get set is part of the issue. In one case, the bounds are compile time constants, which you've captured, currently, with bounded_int. In the quarter2type/half2type case, the bounds are specified at compile time, but actually determined at runtime because they are not compile time constants. That's like creating a const object: once initialized, its value cannot be changed, but the value from which it is initialized can be computed at run time. There's also the case of unfixed bounds that can be changed at runtime, regardless of whether the bounds -- initial or later -- are determined at compile time. Clearly, computing bounds at compile time versus runtime can be considered another dimension added to that of whether the bounds are fixed, so there are four combinations possible: compile time fixed, runtime fixed, compile time unfixed, and runtime unfixed. (The use of "fixed" is unfortunate, because it evokes fixed point numbers, of course.) When the value of the bounds is computed seems relatively unimportant versus whether they can be changed at runtime. Thus, I think there should be two class templates that capture that notion. Each of them might reasonably have a helper that makes specification of compile time constant bounds easier, like your current bounded_int does. If that taxonomy makes sense, then we must consider names, but I'll not go that far unless you agree with this view of the types. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

From: Stewart, Robert Clearly, computing bounds at compile time versus runtime can be considered another dimension added to that of whether the bounds are fixed, so there are four combinations possible: compile time fixed, runtime fixed, compile time unfixed, and runtime unfixed.
I don't get it - what "compile time unfixed" would be?
When the value of the bounds is computed seems relatively unimportant versus whether they can be changed at runtime. Thus, I think there should be two class templates that capture that notion. Each of them might reasonably have a helper that makes specification of compile time constant bounds easier, like your current bounded_int does.
If that taxonomy makes sense, then we must consider names, but I'll not go that far unless you agree with this view of the types.
Well, to be honest I don't see the taxonomy making things simpler, quite the contrary - it implies several implementations instead of just the one. Yet it only imposes unnecessary constraints restricting possible use cases, e.g. with the current "bounded" class template you may easily create objects with one bound that is fixed at compile time and the other being mutable (for instance number of days in a month). I understand that the simplified model of separate classes for fixed/unfixed bounds might look more as expected by a newcomer, but rather than multiplying entities I'd explain the existing model better in the tutorial if it's not explained well enough (is it not?) Best regards, Robert

Robert Kawulak wrote:
From: Stewart, Robert Clearly, computing bounds at compile time versus runtime can be considered another dimension added to that of whether the bounds are fixed, so there are four combinations possible: compile time fixed, runtime fixed, compile time unfixed, and runtime unfixed.
I don't get it - what "compile time unfixed" would be?
The initial values are given with compile time constants, but they can be changed at runtime.
When the value of the bounds is computed seems relatively unimportant versus whether they can be changed at runtime. Thus, I think there should be two class templates that capture that notion. Each of them might reasonably have a helper that makes specification of compile time constant bounds easier, like your current bounded_int does.
If that taxonomy makes sense, then we must consider names, but I'll not go that far unless you agree with this view of the types.
Well, to be honest I don't see the taxonomy making things simpler, quite the contrary - it implies several implementations instead of just the one. Yet it only imposes unnecessary constraints restricting possible use cases, e.g. with the current "bounded" class template you may easily create objects with one bound that is fixed at compile time and the other being mutable (for instance number of days in a month).
I hadn't considered that each bound could be given with a compile time constant or not, and each could be fixed or unfixed.
I understand that the simplified model of separate classes for fixed/unfixed bounds might look more as expected by a newcomer, but rather than multiplying entities I'd explain the existing model better in the tutorial if it's not explained well enough (is it not?)
Given that each bound can be found in the four quadrants independent of the other, your bounded_int class template is restrictive. Don't you need an easier way to supply and configure the bounds so each can be placed into any of the four quadrants independently? Ruminating... bounded simply arranges for the bounds to be of the value type so they can be altered at runtime, right? bounded_int requires compile time constants for both ranges and cannot be changed at runtime. The key characteristic of the latter, to me, is that the bounds are fixed at compile time; they cannot be changed at runtime. However, I get that bounded can also be configured with types that generate an initial value at runtime that cannot be changed thereafter (so they are, effectively of type T const rather than T. Therefore, runtime mutability is not the entire picture for bounded_int. The _c suffix, borrowed from MPL, is good for specifying that the bounds are compile time constants. Adding that to "bounded" seems wrong because the bounded's value can still change, within the confines of the bounds. (The same is true of "static" and "ct" as suffixes or prefixes.) In your example with quarter2type, you show: bounded<rational, quarter2type, half2type> Perhaps the best thing for what you're calling bounded_int is this; bounded<int, bound_c<0>, bound_c<10> > It isn't as succinct as this: bounded_int<int, 0, 10> but it does eliminate the troubling naming problem and, I think, reduces confusion. Consider: bounded<int, bound_c<0>, big_prime> There we combine both ideas without having to introduce anything new. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

From: Stewart, Robert Given that each bound can be found in the four quadrants independent of the other, your bounded_int class template is restrictive.
Of course it is, because it is only meant to be a shortcut in one special and very common case. In all other cases "bounded" is the one to use. Its default template parameters have been designed to simplify the usage in the other common use cases.
Don't you need an easier way to supply and configure the bounds so each can be placed into any of the four quadrants independently?
Is the current way too complicated after looking at the examples in the docs?
bounded simply arranges for the bounds to be of the value type so they can be altered at runtime, right?
By default, yes, but not in general. They may be of any type, see the example with bounded-length string, and depending on the type used they can or can't be altered at runtime.
bounded_int requires compile time constants for both ranges and cannot be changed at runtime. The key characteristic of the latter, to me, is that the bounds are fixed at compile time; they cannot be changed at runtime. However, I get that bounded can also be configured with types that generate an initial value at runtime that cannot be changed thereafter (so they are, effectively of type T const rather than T. Therefore, runtime mutability is not the entire picture for bounded_int.
Yes, this is what I tried to explain. ;-) The key functionality of "bounded_int" is making it easier to specify fixed bounds that can be expressed with a compile-time constant expression. Not ANY fixed bounds.
The _c suffix, borrowed from MPL, is good for specifying that the bounds are compile time constants. Adding that to "bounded" seems wrong because the bounded's value can still change, within the confines of the bounds. (The same is true of "static" and "ct" as suffixes or prefixes.)
That's right, but so far I don't think we've found better names.
In your example with quarter2type, you show:
bounded<rational, quarter2type, half2type>
Perhaps the best thing for what you're calling bounded_int is this;
bounded<int, bound_c<0>, bound_c<10> >
It isn't as succinct as this:
bounded_int<int, 0, 10>
Rather: bounded<int, bound_c<int, 0>, bound_c<int, 10> > ...which is even less succint and redundant - in the bound_c template you would have to specify the type as the first parameter to know what is the type of the second one. Another option is to have something like: template<intmax_t Value> bounded_c; Which has two small issues: - it is usable only for integer constant expressions (no pointers), - it is not usable if one wants to use uintmax_t value too big to be expressed with intmax_t. The issues could be overcame by defining several versions of the template, like: bound_c<typename Type, Type Value> bound_int_c<intmax_t Value> bound_uint_c<uintmax_t Value> Which may make things more complicated.
but it does eliminate the troubling naming problem and, I think, reduces confusion. Consider:
bounded<int, bound_c<0>, big_prime>
Which currently looks like: bounded<int, mpl::int_<0>, big_prime> I can't see a big difference. :P In general, the idea looks interesting and also consistent with the idea of Vicente Botet to specify bounds inclusion like this: bounded<int, open_c<0>, close_c<100> > We could have the bounds specifiers and bounds inclusion specifiers: namespace bound { struct included; // bound always included in the interval struct excluded; // bound always excluded from the interval struct optional; // can be included/excluded at runtime template <typename Type, Type Value, typename Inclusion = included> struct c; // bound as a compile-time constant expression template <intmax_t Value, typename Inclusion = included> struct int_c; // bound as a compile-time constant int template <uintmax_t Value, typename Inclusion = included> struct uint_c; // bound as a compile-time constant uint template <typename Type, typename Inclusion = included> struct of_type; // bound mutable at runtime OR constant expressed with type } This would allow to write: bounded<int, bound::int_c<-10>, bound::int_c<10> > bounded<int, bound::of_type<int>, bound::of_type<int> > bounded<rational, bound::of_type<quarter2type>, bound::of_type<half2type> > bounded<int, bound::int_c<0>, bound::of_type<big_prime> > bounded<int, bound::int_c<0, bound::included>, bound::of_type<int, bound::excluded> > Being more explicit it is also unfortunately more verbose in most cases, compared to the current syntax: bounded_int<int, -10, 10> bounded<int> bounded<rational, quarter2type, half2type> bounded<int, mpl::int_<0>, big_prime> bounded<int, mpl::int_<0>, int, throw_exception<>, mpl::false_, mpl::true_> Implementation of the proposed syntax is relatively easy. However, it has also its weaknesses and maybe should rather be an alternative to than replacement of the current syntax (it could be just another template-typedef for bounded, just as bounded_int is). But then having two possible syntaxes to do exactly the same things sounds like a bad idea... Best regards, Robert

----- Original Message ----- From: "Robert Kawulak" <robert.kawulak@gmail.com> To: <boost@lists.boost.org> Sent: Sunday, October 17, 2010 3:29 AM Subject: Re: [boost] [constrained_value] Constrained Value review results
In general, the idea looks interesting and also consistent with the idea of Vicente Botet to specify bounds inclusion like this:
bounded<int, open_c<0>, close_c<100> >
This would allow to write:
bounded<int, bound::int_c<-10>, bound::int_c<10> > bounded<int, bound::of_type<int>, bound::of_type<int> > bounded<rational, bound::of_type<quarter2type>, bound::of_type<half2type> > bounded<int, bound::int_c<0>, bound::of_type<big_prime> > bounded<int, bound::int_c<0, bound::included>, bound::of_type<int, bound::excluded> >
Being more explicit it is also unfortunately more verbose in most cases, compared to the current syntax:
bounded_int<int, -10, 10> bounded<int> bounded<rational, quarter2type, half2type> bounded<int, mpl::int_<0>, big_prime> bounded<int, mpl::int_<0>, int, throw_exception<>, mpl::false_, mpl::true_>
I was wondering whether the library could not define some more generic logical and comparison constraints so we can do constrained<int, and_<greater_equal<int_<-10> >, less_equal<int_<10> > > > constrained<int, and_<greater_equal<ratio<1,4> >, less_equal<ratio<1,2> > > > constrained<int, and_<greater_equal<int_<0> >, less_equal<big_prime > > > constrained<int, and_<greater<int_<0> >, less_equal<int_<10> > > > This will cover all the bounded cases with inclusion or exclusion of the bound. Best, Vicente

From: vicente.botet I was wondering whether the library could not define some more generic logical and comparison constraints so we can do
constrained<int, and_<greater_equal<int_<-10> >, less_equal<int_<10> > > > constrained<int, and_<greater_equal<ratio<1,4> >, less_equal<ratio<1,2> > > > constrained<int, and_<greater_equal<int_<0> >, less_equal<big_prime > > > constrained<int, and_<greater<int_<0> >, less_equal<int_<10> > > >
Similar thing, but based on lambdas, was already suggested by Gordon Woodhull and Stjepan Rajko was attempting to do this with Boost.Phoenix. I don't know if this functionality is already included in that library. That's the discussion: http://groups.google.com/group/boostusers/browse_thread/thread/91e63d27da5bd... Best regards, Robert

On Oct 28, 2010, at 7:21 PM, Robert Kawulak <robert.kawulak@gmail.com> wrote:
From: vicente.botet I was wondering whether the library could not define some more generic logical and comparison constraints so we can do
constrained<int, and_<greater_equal<int_<-10> >, less_equal<int_<10> > > > constrained<int, and_<greater_equal<ratio<1,4> >, less_equal<ratio<1,2> > > > constrained<int, and_<greater_equal<int_<0> >, less_equal<big_prime > > > constrained<int, and_<greater<int_<0> >, less_equal<int_<10> > > >
Similar thing, but based on lambdas, was already suggested by Gordon Woodhull and Stjepan Rajko was attempting to do this with Boost.Phoenix. I don't know if this functionality is already included in that library. That's the discussion:
http://groups.google.com/group/boostusers/browse_thread/thread/91e63d27da5bd...
Heh heh. That was a fun idea: that in theory you could produce perfectly efficient predicates without boost::function, possibly even zero-size. Unfortunately Stjepan found that Phoenix was not designed to produce small enough functors to serve as good predicates for constrained. It would take a redesigned Phoenix or another library to do this sort of thing right.

----- Original Message ----- From: "Gordon Woodhull" <gordon@woodhull.com> To: <boost@lists.boost.org> Sent: Friday, October 29, 2010 5:25 AM Subject: Re: [boost] [constrained_value] Constrained Value review results
On Oct 28, 2010, at 7:21 PM, Robert Kawulak <robert.kawulak@gmail.com> wrote:
From: vicente.botet I was wondering whether the library could not define some more generic logical and comparison constraints so we can do
constrained<int, and_<greater_equal<int_<-10> >, less_equal<int_<10> > > > constrained<int, and_<greater_equal<ratio<1,4> >, less_equal<ratio<1,2> > > > constrained<int, and_<greater_equal<int_<0> >, less_equal<big_prime > > > constrained<int, and_<greater<int_<0> >, less_equal<int_<10> > > >
Similar thing, but based on lambdas, was already suggested by Gordon Woodhull and Stjepan Rajko was attempting to do this with Boost.Phoenix. I don't know if this functionality is already included in that library. That's the discussion:
http://groups.google.com/group/boostusers/browse_thread/thread/91e63d27da5bd...
Heh heh. That was a fun idea: that in theory you could produce perfectly efficient predicates without boost::function, possibly even zero-size.
Yes, this is what I expect for these constraints efficiency and zero-size.
Unfortunately Stjepan found that Phoenix was not designed to produce small enough functors to serve as good predicates for constrained. It would take a redesigned Phoenix or another library to do this sort of thing right.
I don't know what problems Phoenix has. Maybe we need to wait for a new library, but in the context of the Constraint library I find that all these predicates are no so hard to implement and will give a real power to the library. Just my 2 cts. Vicente

On Oct 29, 2010, at 8:56 AM, "vicente.botet" <vicente.botet@wanadoo.fr> wrote:
I don't know what problems Phoenix has. Maybe we need to wait for a new library, but in the context of the Constraint library I find that all these predicates are no so hard to implement and will give a real power to the library.
I don't think they necessarily belong to this library but they would make a nice companion - constraints to go along with the constrained values... To spell it out, I think we are talking about a set of predicates sort of like those in std:: except that one of the arguments is bound to a static value. Right? constexpr is going to be very nice for constrained_value!

----- Original Message ----- From: "Gordon Woodhull" <gordon@woodhull.com> To: <boost@lists.boost.org> Sent: Friday, October 29, 2010 4:45 PM Subject: Re: [boost] [constrained_value] Constrained Value review results
On Oct 29, 2010, at 8:56 AM, "vicente.botet" <vicente.botet@wanadoo.fr> wrote:
I don't know what problems Phoenix has. Maybe we need to wait for a new library, but in the context of the Constraint library I find that all these predicates are no so hard to implement and will give a real power to the library.
I don't think they necessarily belong to this library but they would make a nice companion - constraints to go along with the constrained values...
Unfortunately if they a re not added in the library we will need to wait for a volunter to provide someting like that as a separated library. Think for example on the Serialize library. There are two separated part archive and serialization. You could have two parts constraint and constrained_value.
To spell it out, I think we are talking about a set of predicates sort of like those in std:: except that one of the arguments is bound to a static value. Right?
Right.
constexpr is going to be very nice for constrained_value!
Yes, I agree. constexpr will help a lot of libraries and applications that need to improve the performance to the point to make some computations at compile time :) Best, Vicente

On Oct 29, 2010, at 12:14 PM, "vicente.botet" <vicente.botet@wanadoo.fr> wrote:
I don't think they necessarily belong to this library but they would make a nice companion - constraints to go along with the constrained values...
Unfortunately if they are not added in the library we will need to wait for a volunter to provide someting like that as a separated library. Think for example on the Serialize library. There are two separated part archive and serialization. You could have two parts constraint and constrained_value.
Yeah, this would be a great place for such a library to start, which would be easier than starting it from scratch. I don't think Robert necessarily has to write it, though. It could be contributed as an extension. (Please insert standard apology for suggesting work for someone else to do.) Gordon

Robert Kawulak wrote:
From: Stewart, Robert
Given that each bound can be found in the four quadrants independent of the other, your bounded_int class template is restrictive.
Of course it is, because it is only meant to be a shortcut in one special and very common case. In all other cases "bounded" is the one to use. Its default template parameters have been designed to simplify the usage in the other common use cases.
Part of the problem in this discussion has been understanding the supported use cases and then how constrained can be applied to them. It is also easy to get mired in the details when one is just trying to understand what the library offers the newcomer. I suggest that your documentation present a list of the supported use cases and then develop them according to some measure of frequency of use or, perhaps more appropriate, by increasing complexity. IOW, the list should be complete, and allow random access to the various use cases, but for the sequential reader -- the newcomer -- you want to present the idea starting with the simplest ways to use the library and advancing from there. At the top of such a list are, I think, predicate-based constraints and compile-time ranges. Your first example, with is_even, is fine, except that it, like the rest, should be written from the perspective of being found via random access. That is, don't build one example upon another assuming they are read in order, but rather assume the reader has jumped into them randomly based upon thinking they apply to a current need. After predicate-based constraints, you should introduce compile-time bounds. The 0-100 percent example is good, but there's too much implementation detail for a tutorial and the phrasing needs help. I suggest something more like the following: _______________________________________ A common use case is specifying value constraints based upon compile time constants that never change thereafter. For example, a progress value can vary from zero to 100 percent. Any value outside that range is invalid. constrained supports such constraints as can be seen by this verbose and complicated type: typedef constrained<put line noise here> percent; To make such constraints easy to specify, the library provides the following, alternative syntax: typedef bounded_int<int, 0, 100>::type percent; percent p; p = 50; // OK p = 200; // Exception! For more on how bounded_int works and its relationship to constrained, look here(link). The bounds for bounded_int are part of the type so they occupy no space and cannot be changed at runtime. Accordingly, the bounds can be accessed at compile time or at runtime: BOOST_STATIC_ASSERT(percent::constraint_type::upper_type::value == 100); assert(p.constraint().upper_bound() == 100); Note: The constrained type must be one of the types allowed as a non-type template parameter, which means integral types and some pointer types). _______________________________________ (I think that "upper_type" should be "upper_bound_type" because you use "_bound" in most contexts.)
From there you can provide examples for the types-as-values, bounded objects (within_bounds), and open ranges. For the former and latter cases, your examples explain too little as you assume the reader is familiar with boost::rational.
In the types-as-values example, your explanation should include text to the effect that, "quarter2type and half2type are defined to always return the same bounds, even though the bounds are computed at runtime. Thus, they are a degenerate case of the more general case described here(link)." The link would be to another use case showing how the type's function call operator can provide a value at runtime. I find your justification of bounded_int weak. You claim it handles a "very common use case," which I don't dispute, but shouldn't the justification be that the syntax using "constrained" is awkward, verbose, or complex? If you agree with that, then there may be other use cases that deserve special treatment (assuming bounded doesn't already handle them neatly). Given a complete list of supported use cases, it would be easier to judge the need for other simplifications.
Don't you need an easier way to supply and configure the bounds so each can be placed into any of the four quadrants independently?
Is the current way too complicated after looking at the examples in the docs?
Given the organization of the docs, things are still awkward. You start with "constrained," move to "bounded," and finally to "bounded_int" in fairly short order. When I reach the end of the tutorial, I'm left uneasy about which I would need for a given purpose. My suggestion for how to reorganize the tutorial will help with that. If each simplification (bounded, bounded_int, and anything else that may arise) were clearly documented -- not in the tutorial -- WRT to constrained, it would also help. That is, from the tutorial, after reading about bounded_int, for example, a link to more detailed documentation that shows how bounded_int is a specialization of constrained would be helpful. It would explain that constrained is the foundational component and how bounded_int uses it. By putting that text elsewhere, however, the tutorial is simpler to read. (My suggestion that shows the ugly constrained specialization needed for the simple bounded_int<int, 0, 100> would be the right place for such a link. Indeed, I've just gone back now and added it to my earlier suggestion!)
bounded simply arranges for the bounds to be of the value type so they can be altered at runtime, right?
By default, yes, but not in general. They may be of any type, see the example with bounded-length string, and depending on the type used they can or can't be altered at runtime.
This is another use case that should be documented.
bounded_int requires compile time constants for both ranges and cannot be changed at runtime. The key characteristic of the latter, to me, is that the bounds are fixed at compile time; they cannot be changed at runtime. However, I get that bounded can also be configured with types that generate an initial value at runtime that cannot be changed thereafter (so they are, effectively of type T const rather than T. Therefore, runtime mutability is not the entire picture for bounded_int.
Yes, this is what I tried to explain. ;-) The key functionality of "bounded_int" is making it easier to specify fixed bounds that can be expressed with a compile-time constant expression. Not ANY fixed bounds.
I'm glad I'm starting to make sense of this stuff.
The _c suffix, borrowed from MPL, is good for specifying that the bounds are compile time constants. Adding that to "bounded" seems wrong because the bounded's value can still change, within the confines of the bounds. (The same is true of "static" and "ct" as suffixes or prefixes.)
That's right, but so far I don't think we've found better names.
None of the names is good and I haven't thought of one that would work well. That's why I've been suggesting alternative syntaxes that use bounded (or constrained) so that we don't need a name for what's defying a meaningful name.
In your example with quarter2type, you show:
bounded<rational, quarter2type, half2type>
Perhaps the best thing for what you're calling bounded_int is this;
bounded<int, bound_c<0>, bound_c<10> >
It isn't as succinct as this:
bounded_int<int, 0, 10>
Rather:
bounded<int, bound_c<int, 0>, bound_c<int, 10> >
...which is even less succint and redundant - in the bound_c template you would have to specify the type as the first parameter to know what is the type of the second one.
Quite right. However, given that bounded_int is only trying to handle the case of both bounds being compile time constants, maybe this would work: bounded<int, bounds_c<int, 0, 100> > (If within_bounds were renamed to just "bounds," the two would be parallels.) That repeats "int," sadly, but it doesn't introduce a new name for the main class template; it reuses bounded.
Another option is to have something like:
template<intmax_t Value> bounded_c;
Which has two small issues:
- it is usable only for integer constant expressions (no pointers), - it is not usable if one wants to use uintmax_t value too big to be expressed with intmax_t.
The issues could be overcame by defining several versions of the template, like:
bound_c<typename Type, Type Value> bound_int_c<intmax_t Value> bound_uint_c<uintmax_t Value>
Which may make things more complicated.
That's not bad.
but it does eliminate the troubling naming problem and, I think, reduces confusion. Consider:
bounded<int, bound_c<0>, big_prime>
Which currently looks like:
bounded<int, mpl::int_<0>, big_prime>
I can't see a big difference. :P
There isn't a big difference, but "mpl::int_" looks daunting to those unused to MPL.
In general, the idea looks interesting and also consistent with the idea of Vicente Botet to specify bounds inclusion like this:
bounded<int, open_c<0>, close_c<100> >
Nice!
We could have the bounds specifiers and bounds inclusion specifiers:
namespace bound {
struct included; // bound always included in the interval struct excluded; // bound always excluded from the interval struct optional; // can be included/excluded at runtime
template <typename Type, Type Value, typename Inclusion = included> struct c; // bound as a compile-time constant expression
template <intmax_t Value, typename Inclusion = included> struct int_c; // bound as a compile-time constant int
Can/should this support optional? Giving the initial value using a compile time constant is not unreasonable, but is it wise to provide for that use case? Might it be better to require runtime initialization of runtime changeable bounds?
template <uintmax_t Value, typename Inclusion = included> struct uint_c; // bound as a compile-time constant uint
Ditto
template <typename Type, typename Inclusion = included> struct of_type; // bound mutable at runtime OR constant expressed with type
}
This would allow to write:
bounded<int, bound::int_c<-10>, bound::int_c<10> > bounded<int, bound::of_type<int>, bound::of_type<int> > bounded<rational, bound::of_type<quarter2type>, bound::of_type<half2type> > bounded<int, bound::int_c<0>, bound::of_type<big_prime> > bounded<int, bound::int_c<0, bound::included>, bound::of_type<int, bound::excluded> >
Being more explicit it is also unfortunately more verbose in most cases, compared to the current syntax:
bounded_int<int, -10, 10>
This is implicitly inclusive of the bounds which restricts its use still further. By contrast, using the following makes the bounds inclusion explicit thereby reducing the chance for confusion: using bound::int_c; using bound::excluded; bounded<int, int_c<-10, excluded>, int_c<10> > This avoids the need to name what is defying a good name and increases flexibility and clarity while only slightly reducing the brevity. Obviously, I'm transferring the need to know that bounded_int is inclusive of its bounds to int_c's default, but as int_c can be used in multiple contexts, it's a more useful building block and increases the flexibility of using bounded (versus using bounded_int).
bounded<int> bounded<rational, quarter2type, half2type> bounded<int, mpl::int_<0>, big_prime> bounded<int, mpl::int_<0>, int, throw_exception<>, mpl::false_, mpl::true_>
The last of those isn't meaningful at a glance. What do the Booleans mean at the end? One has to count parameters and match them to the arguments. Clearly, one could created named Booleans -- "included" and "excluded" for example -- but it should rather be expressed something like this, given your previous idea: bounded<int, int_c<0>, of_type<int, excluded> >
Implementation of the proposed syntax is relatively easy. However, it has also its weaknesses and maybe should rather be an alternative to than replacement of the current syntax (it could be just another template-typedef for bounded, just as bounded_int is).
I'm not sure the weaknesses are significant.
But then having two possible syntaxes to do exactly the same things sounds like a bad idea...
I agree with that to a point. You already provide multiple ways of doing things, however: constrained, bounded, and bounded_int. The right way to view that is to make the common easy and the less common possible. That's also why I suggested writing your tutorial beginning with the simple use cases: it illustrates how easy the common use cases are and moves on to the less common use cases which, while not so easy, are still supported. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

From: Stewart, Robert
I suggest that your documentation present a list of the supported use cases and then develop them according to some measure of frequency of use or, perhaps more appropriate, by increasing complexity.
Thanks for the suggestions, I'll try to make the docs more clear.
The _c suffix, borrowed from MPL, is good for specifying that the bounds are compile time constants. Adding that to "bounded" seems wrong because the bounded's value can still change, within the confines of the bounds. (The same is true of "static" and "ct" as suffixes or prefixes.)
That's right, but so far I don't think we've found better names.
None of the names is good and I haven't thought of one that would work well. That's why I've been suggesting alternative syntaxes that use bounded (or constrained) so that we don't need a name for what's defying a meaningful name.
Changing the syntax for bounded or not, I wouldn't want to give up providing something as convenient as bounded_int (or let it be bounded_ct) just because we couldn't find a better name. Compare bounded<int, bound::int_c<0>, bound::int_c<10>> to bounded_ct<int, 0, 10> Moreover, consider this erroneous case: bounded<unsigned char, bound::int_c<-10>, bound::int_c<1000> > A sufficiently smart compiler could warn in such case, but the warning would point to implementation details (comparison of unsigned char and int in within_bounds class). This, however, will make it complain with clear indication of the error: bounded_ct<unsigned char, -10, 1000>
We could have the bounds specifiers and bounds inclusion specifiers:
namespace bound {
struct included; // bound always included in the interval struct excluded; // bound always excluded from the interval struct optional; // can be included/excluded at runtime
template <typename Type, Type Value, typename Inclusion = included> struct c; // bound as a compile-time constant expression
template <intmax_t Value, typename Inclusion = included> struct int_c; // bound as a compile-time constant int
Can/should this support optional? Giving the initial value using a compile time constant is not unreasonable, but is it wise to provide for that use case? Might it be better to require runtime initialization of runtime changeable bounds?
I'm not sure I understand you. What bound::optional means is that the bound can be "opened"/"closed" at runtime; that is, you may switch between [0, 10] and (0, 10] independently to the fact whether the bound's value is fixed or mutable. I know "optional" may be confusing at first encounter, but so far I haven't found a better name.
Being more explicit it is also unfortunately more verbose in most cases, compared to the current syntax:
bounded_int<int, -10, 10>
This is implicitly inclusive of the bounds which restricts its use still further.
It doesn't restrict its use - you may change bounds inclusion by specifying subsequent template arguments. The defaults are to include bounds, which is the more common use case.
bounded<int> bounded<rational, quarter2type, half2type> bounded<int, mpl::int_<0>, big_prime> bounded<int, mpl::int_<0>, int, throw_exception<>, mpl::false_, mpl::true_>
The last of those isn't meaningful at a glance. What do the Booleans mean at the end? One has to count parameters and match them to the arguments. Clearly, one could created named Booleans -- "included" and "excluded" for example
This is exactly what came to my mind just after I sent my reply. bounds::included, bounds::excluded and bounds::optional mentioned above can be defined anyway, even for the old syntax. Why I haven't thought of this earlier... ;-) So let's see it again. To express the following intervals ("?" means bound mutable at runtime): int [-10, 10] int [?, ?] rational [1/4, 1/2] big_int [0, big_prime] unsigned [42, ?) The new way: bounded<int, bound::int_c<-10>, bound::int_c<10> > bounded<int, bound::of_type<int>, bound::of_type<int> > bounded<rational, bound::of_type<quarter2type>, bound::of_type<half2type> > bounded<big_int, bound::int_c<0>, bound::of_type<big_prime> > bounded<unsigned, bound::uint_c<42, bound::included>, bound::of_type<unsigned, bound::excluded> > The current way: bounded<int, mpl::int_<-10>, mpl::int_<10> > bounded<int> bounded<rational, quarter2type, half2type> bounded<big_int, mpl::int_<0>, big_prime> bounded<unsigned, mpl::integral_c<unsigned, 0>, unsigned, throw_exception<>, bound::included, bound::excluded> I have yet another idea, somehow merging the two syntaxes. It looks like the current syntax as long as you don't specify bounds inclusion explicitly, in which case it would look similar to the new syntax: bounded<int, mpl::int_<-10>, mpl::int_<10> > bounded<int> bounded<rational, quarter2type, half2type> bounded<big_int, mpl::int_<0>, big_prime> bounded<unsigned, bound<mpl::integral_c<unsigned, 0>, included>, bound<unsigned, excluded> >
I agree with that to a point. You already provide multiple ways of doing things, however: constrained, bounded, and bounded_int.
Yes, but those are slightly different things (each one is a special case of another), while providing two syntaxes for bounded would really be two ways to do exactly the same.
The right way to view that is to make the common easy and the less common possible.
Both the syntaxes are equivalent in terms of possibilities. The tradeoff is higher verbosity in most cases (the new syntax) vs. obscurity in less common cases (the current syntax). Best regards, Robert

----- Original Message ----- From: "Robert Kawulak" <robert.kawulak@gmail.com> To: <boost@lists.boost.org> Sent: Friday, October 08, 2010 6:10 PM Subject: Re: [boost] [constrained_value] Constrained Value review results 2010/10/8 Stewart, Robert <Robert.Stewart@sig.com>:
You mean "bound" as past participle of "to bind", so "ct_bound" would mean something that has been bound (i.e., "binded") at compile time? I think the operation we want to express is bounding rather than binding...
I see the bounds as being applied at compile time, so it is bound to the specified range at compile time, so, yes, I meant the past participle of the infinitive "to bind." That the bounds continue to apply at runtime after having been bound at compile time is not, I think, the principle distinction.
But applying fixed bounds at compile time is not a defining characteristic of "bounded_int", it is using compile time constant expressions to specify the bounds.
ct_bounded<int> rt_bounded<short>
The former is the subset of the latter, so "rt_bounded" is not a good idea since it may represent objects with compile-time-fixed bounds as well. I think just "bounded" is the best.
Strictly speaking, runtime bounded is not a superset of compile time bounded, because one cannot choose to do either with the runtime bounded class, right? [...] Thus, "bounded" is insufficient for the runtime version as that name implies both categories and does not clearly suggest the runtime variability.
-1 "bounded"
I'm not trying to say that runtime bounded is a superset of compile time bounded, but that "bounded" is a superset of "bounded_int". You can use "bounded" with static or dynamic bounds. There are even cases when "bounded_int" cannot be used to define static bounds and you have to use "bounded" instead – these are all the cases where the bounds cannot be expressed directly using compile time constant expressions, e.g. for floats or rational numbers. See the example with rational numbers in the second part of this subsection: http://tinyurl.com/332vmf5#constrained_value.tutorial.compile_time_fixed_bou... Best regards, Robert _______________________________________________ Hi, I was wondering if we could not use Boost.Ratio to specify compile time bounds for boost::rational. So instead of bounded<rational, quarter2type, half2type>::type my_rational(rational(1, 2)); we can do static_bounded<rational, ratio<1,4>, ratio<1,2> >::type my_rational(rational(1, 2)); We can consider that ratio is the rational_constant of rational as integral_constant is the tpe constant for integral types. Of cousre, we will need to use a comparator that would be able to compare ratio and rational. template <intmax_t N, intmax_t D> bool operator<(rational<intmax_t> const& lhs, ratio<N,D> rhs); template <intmax_t N, intmax_t D> bool operator<(ratio<N,D> lhs, rational<intmax_t> const& rhs); I don't know if there are applications that need this performance gain, but how knows. Best, Vicente

2010/10/8 vicente.botet <vicente.botet@wanadoo.fr>:
I was wondering if we could not use Boost.Ratio to specify compile time bounds for boost::rational. So instead of
bounded<rational, quarter2type, half2type>::type my_rational(rational(1, 2));
we can do
static_bounded<rational, ratio<1,4>, ratio<1,2> >::type my_rational(rational(1, 2));
Not static_bounded, but rather bounded<rational, ratio<1,4>, ratio<1,2> >::type. ratio<1,4> is a type, not a compile time constant. Once again I'll try to explain – static_bounded (bounded_int, bounded_ct or whatever we call it) is not exactly for bounds fixed at compile time, but for bounds values of which can be expressed by compile time constants.
We can consider that ratio is the rational_constant of rational as integral_constant is the tpe constant for integral types. Of cousre, we will need to use a comparator that would be able to compare ratio and rational.
template <intmax_t N, intmax_t D> bool operator<(rational<intmax_t> const& lhs, ratio<N,D> rhs); template <intmax_t N, intmax_t D> bool operator<(ratio<N,D> lhs, rational<intmax_t> const& rhs);
Or even simpler – make ratio implicitly convertible to rational. Either way, the best place for this functionality is probably the rational class. Best regards, Robert

----- Original Message ----- From: "Robert Kawulak" <robert.kawulak@gmail.com> To: <boost@lists.boost.org> Sent: Friday, October 08, 2010 7:45 PM Subject: Re: [boost] [constrained_value] Constrained Value review results 2010/10/8 vicente.botet <vicente.botet@wanadoo.fr>:
I was wondering if we could not use Boost.Ratio to specify compile time bounds for boost::rational. So instead of
bounded<rational, quarter2type, half2type>::type my_rational(rational(1, 2));
we can do
static_bounded<rational, ratio<1,4>, ratio<1,2> >::type my_rational(rational(1, 2));
Not static_bounded, but rather bounded<rational, ratio<1,4>, ratio<1,2> >::type. ratio<1,4> is a type, not a compile time constant. Once again I'll try to explain – static_bounded (bounded_int, bounded_ct or whatever we call it) is not exactly for bounds fixed at compile time, but for bounds values of which can be expressed by compile time constants.
We can consider that ratio is the rational_constant of rational as integral_constant is the tpe constant for integral types. Of cousre, we will need to use a comparator that would be able to compare ratio and rational.
template <intmax_t N, intmax_t D> bool operator<(rational<intmax_t> const& lhs, ratio<N,D> rhs); template <intmax_t N, intmax_t D> bool operator<(ratio<N,D> lhs, rational<intmax_t> const& rhs);
Or even simpler – make ratio implicitly convertible to rational. Either way, the best place for this functionality is probably the rational class. Best regards, Robert _______________________________________________ Sorr bau I dont see the difference. I consider ratio<N,D> to express a compile time constant through a type, as integral_c or integral_constant do. If ratio is converible to rational, all the optimizations oportunities could be lost as we will compare two run time types. Best, Vicente

On 5 October 2010 20:43, Robert Kawulak <robert.kawulak@gmail.com> wrote:
Hello All,
As Gordon Woodhull has suggested, it'd be nice to try finding a better name for bounded_int:
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time.
I think bounded_int or bounded_integral seems just fine. The class' compile time parameters and runtime parameters I assume the user can find in the documentation. From the header synopsis you gave in previous post it was already quite clear the interface. I can't imagine you'd later get a name collision with another bounded_integral which has runtime bounds (one doesn't need to restrict oneself to integers if those values specified at runtime). Just my 2 pesos, christian

Den 06-10-2010 14:46, Christian Holmquist skrev:
On 5 October 2010 20:43, Robert Kawulak<robert.kawulak@gmail.com> wrote:
Hello All,
As Gordon Woodhull has suggested, it'd be nice to try finding a better name for bounded_int:
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time.
I think bounded_int or bounded_integral seems just fine. The class' compile time parameters and runtime parameters I assume the user can find in the documentation. From the header synopsis you gave in previous post it was already quite clear the interface.
bounded_int and bounded_float is fine with me too. Since the library is called constrained_value, contrained_int and constrained_float would be fine too. -Thorsten

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Thorsten Ottosen Sent: Wednesday, October 06, 2010 2:21 PM To: boost@lists.boost.org Subject: Re: [boost] [constrained_value] Constrained Value review results
Den 06-10-2010 14:46, Christian Holmquist skrev:
On 5 October 2010 20:43, Robert Kawulak<robert.kawulak@gmail.com> wrote:
Hello All,
As Gordon Woodhull has suggested, it'd be nice to try finding a better name for bounded_int:
The unique characteristic of this class is not that it's bounded or an int, but that the bounds are specified at compile time.
I think bounded_int or bounded_integral seems just fine. The class' compile time parameters and runtime parameters I assume the user can find in the documentation. From the header synopsis you gave in previous post it was already quite clear the interface.
bounded_int and bounded_float is fine with me too. Since the library is called constrained_value, contrained_int and constrained_float would be fine too.
Although most of the types are integral rather than floats, _int or _integral feels misleading. Doesn't the template parameter tell you the type? (If you care). I also like the word 'static' - it implies 'fixed at compile time' to me, but I agree static has other possible implications. So fixed_bound is my suggestion, FWIW. fixed_bound<int, 0, 23>::type hour; Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

Den 14-09-2010 03:20, Robert Kawulak skrev:
From: Gordon Woodhull All of the items in section 3 must be addressed at least in documentation. In some cases, they can only be addressed that way ("Substitutability with the underlying type", "Constraints not copied when operators used").
To my memory, no one asked for a second review, so it is my judgment that once Robert has addressed section 3 the library can be released. Robert, please post any objections.
You want to say literally all? I mean, some of the points were rather suggestions or minor requests (at least I felt so) or had no clear conclusion, e.g. "seralization" or "rename bounded_int", to name a few. For some of them I don't see how I could address them in documentation or why should they be crucial for final acceptance (don't get me wrong - I'm open for suggestions, but for instance if I were to add all the examples suggested by people to the docs, it would become too bloated and out of topic. A software maintainer can't do everything to please anybody but has to choose which requests to implement and which not to). To conclude - I don't feel section 3 contains only major issues, so should all of them be crucial for acceptance?
At least when it comes to naming, and possibly other issues, it is customary to make a vote on the list to get some guideance and consensus. -Thorsten
participants (12)
-
Christian Holmquist
-
Dave Abrahams
-
Gordon Woodhull
-
Klaim
-
Krzysztof Czainski
-
Neal Becker
-
OvermindDL1
-
Paul A. Bristow
-
Robert Kawulak
-
Stewart, Robert
-
Thorsten Ottosen
-
vicente.botet