[Review] Quantitative Units library review begins today, March 26

The review for the Quantitative Units library, submitted by Matthias Schabel and Steven Watanabe begins today, March 26 and ends April 4. From the documentation: The Boost.Units library is a C++ implementation of zero runtime overhead compile-time dimensional analysis in a general and extensible manner, treating it as a generic metaprogramming problem. Support for units and quantities (defined as a unit and associated value) for arbitrary unit system models and arbitrary value types is provided, as is a general facility for unit conversions enabling fine-grained control over conversion. Complete SI and CGS unit system models are provided, along with systems for angles measured in degrees, gradians, and radians. A small subset of the SI system including only length, mass, and time is developed in the examples as a demonstration of the relative ease of adding new unit systems and the extensibility of the library architecture. In this review, the authors and I expect that there will be active discussions on two topics. In every review there is a discussion of the quality of the library implementation and documentation, and it is obviously expected and desired here. Also, since this library is specifically designed as a compile time library with no attempt to provide unit conversions or other runtime facilities it is expected that the review will include an active thread on whether this is the correct design decision. In specific, this is a different approach than that taken by Andy Little's submission of last year. Because some people will be more interested in one or another of these two discussions, I request that everyone clearly marks comment topics to show which they are discussing. This will also improve Matthias' and Steven's ability to respond usefully and my ability to produce review results and recommendations that accurately reflect the desires of the boost community. In general, please include the following in your review. Your comments may be brief or lengthy, but basically the Review Manager needs your evaluation of the library. If you identify problems along the way, please note if they are minor, serious, or showstoppers. Here are some questions you might want to answer in your review: • What is your evaluation of the design? • What is your evaluation of the implementation? • What is your evaluation of the documentation? • What is your evaluation of the potential usefulness of the library? • Did you try to use the library? With what compiler? Did you have any problems? • How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? • Are you knowledgeable about the problem domain? And finally, every review should answer this question: • Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. Review comments can be sent to the developer list, the user list, or directly to me if you don't wish to comment publicly. Thank you in advance for your time and work in this review. John Phillips Review Manager

My original post did not properly include the address where you can get the library. Below it is updated to do so. Sorry for the inconvenience. John The review for the Quantitative Units library, submitted by Matthias Schabel and Steven Watanabe begins today, March 26 and ends April 4. The library is available at http://www.boost-consulting.org/vault/index.php?action=downloadfile&filename =mcs_units_v0.5.8.zip&directory=Units& With the name mcs_units_v0.7.2.zip Other entries in this directory are not the library up for review. From the documentation: The Boost.Units library is a C++ implementation of zero runtime overhead compile-time dimensional analysis in a general and extensible manner, treating it as a generic metaprogramming problem. Support for units and quantities (defined as a unit and associated value) for arbitrary unit system models and arbitrary value types is provided, as is a general facility for unit conversions enabling fine-grained control over conversion. Complete SI and CGS unit system models are provided, along with systems for angles measured in degrees, gradians, and radians. A small subset of the SI system including only length, mass, and time is developed in the examples as a demonstration of the relative ease of adding new unit systems and the extensibility of the library architecture. In this review, the authors and I expect that there will be active discussions on two topics. In every review there is a discussion of the quality of the library implementation and documentation, and it is obviously expected and desired here. Also, since this library is specifically designed as a compile time library with no attempt to provide unit conversions or other runtime facilities it is expected that the review will include an active thread on whether this is the correct design decision. In specific, this is a different approach than that taken by Andy Little's submission of last year. Because some people will be more interested in one or another of these two discussions, I request that everyone clearly marks comment topics to show which they are discussing. This will also improve Matthias' and Steven's ability to respond usefully and my ability to produce review results and recommendations that accurately reflect the desires of the boost community. In general, please include the following in your review. Your comments may be brief or lengthy, but basically the Review Manager needs your evaluation of the library. If you identify problems along the way, please note if they are minor, serious, or showstoppers. Here are some questions you might want to answer in your review: • What is your evaluation of the design? • What is your evaluation of the implementation? • What is your evaluation of the documentation? • What is your evaluation of the potential usefulness of the library? • Did you try to use the library? With what compiler? Did you have any problems? • How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? • Are you knowledgeable about the problem domain? And finally, every review should answer this question: • Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. Review comments can be sent to the developer list, the user list, or directly to me if you don't wish to comment publicly. Thank you in advance for your time and work in this review. John Phillips Review Manager

Hi John,
In this review, the authors and I expect that there will be active discussions on two topics. In every review there is a discussion of the quality of the library implementation and documentation, and it is obviously expected and desired here. Also, since this library is specifically designed as a compile time library with no attempt to provide unit conversions or other runtime facilities it is expected that the review will include an active thread on whether this is the correct design decision. In specific, this is a different approach than that taken by Andy Little's submission of last year.
Just a quick clarification about the library : while there is no support of parsing of unit/quantity input at runtime or for dynamically processing such runtime units, unit conversions are fully supported at compile time... Matthias

* What is your evaluation of the design? Overall, the library design is very good. I particularly like the fact the user-defined value types, std::complex, etc., work so effortlessly with the library. The support for and integration of trig and cmath functions is great as well. However, I have one strong objection. What is the rationale behind providing the mutating value() member function, and functions from_value() and quantity_cast() for converting raw scalar values into quantities? I really like the default rules on construction of quantities. "quantity<force> F(2.0*newton);" is clear, unabmiguous, and literate. The holes in this system opened by the above functions make me less certain of the library's safety. The mutating value() function is particularly egregious. It allows the arbitrary violation of the quantity's class invariants. I want to be able to construct a set of quantities using their constructors, and thereafter be able to know, without checking through the code for abuses of value(), etc., that they and the results of any math done using them, are well-formed quantities. That is, I want Boost.Units to be hermetically sealed as much as is possible, so that I know that if I specify the units and values correctly at construction, I don't have to think about correctness after that. Mutable value() and quantity_cast(), and to a lesser extent from_value(), mean I have to work a lot harder (read: look in a lot more places) to ensure that my code is correct. Specifically, quantity<force> F(2.0*newton); quantity<length> dx(2.0*meter); F.value() = dx.value(); is an abomination and should be impossible. If I really want to do this, why not make me go through the constructor, so that attention is more obviously called to what I'm doing? I could also live with using a purposely ugly cast here, but since quantity_cast() has some perfectly legitimate and safe uses, I would much prefer a different syntax that draws attention to this unsafe act, such as quantity_reinterpret_cast(). * What is your evaluation of the implementation? Very good. The code is very easy to read and follow, and there seems to be attention paid to all the usual gotchas, like ODR and ADL. Some specifics: Why in the output of quantities are the negative exponents in parentheses? It seems a little odd that negative whole numbers do, and positive whole numbers do not. I and a lot of other users badly need support for Imperial units. As it stands now, we will each be required to write nearly identical code to do so. This should be included in the library. You might want to reserve all system ordinal numbers below 1000 or 10000 for Boost.Units, instead of stopping at 100. There are plenty more numbers for users to choose from, and though 100 might sound like plenty now, you never know how many you might need. * What is your evaluation of the documentation? It's a good start :). The documentation is clear and relatively easy for me to follow. However, there needs to be more discussion of concepts and how to extend the library by adding one's own value types, units, and systems. Here are some specific notes about the docs: In the Units intro text, I believe in the sentence, "Units are, like composite dimensions, purely compile-time variables with no associated value.", variables should be entities. Units are not variables per se. The text in Units that reads "The macro A convenience macro that allows definition of static constants in headers in an ODR-safe way. ..." should instead read "". The macro BOOST_UNITS_STATIC_CONSTANT ...". Also, the description of what this macro does leaves something to be desired. Specifically, do I need to assign any of these static constants an actual value? The macro does not do so. Why does the example include singular and plural forms of the unit types ("meter" and "meters", etc.)? In example 1, it looks like you duplicated the first code block. It looks like the (unit_example_*.cpp) links are broken for all examples, though I only tried the first 5. There appear to be lots of other non-links that are underlined and that look like they should be links, for instance power_typeof_helper and root_typeof_helper in several places. Examples 14, 15, and 18 consist of a single line each. Was this intentional? In example 19, the link to boost/units/systems/si/codata_constants.hpp brings up a basically empty page. In the reference page, several cmath.hpp and io.hpp are missing their contents (functions, macros, etc.). As mentioned in the TODO, there is no concept documentation. While this is not strictly necessary to use much of the library, it should at a minimum include concept requirements for quantity::value_type so that people can create their own Units-compatible types. * What is your evaluation of the potential usefulness of the library? *Extremely* useful. The ability to have dimensional analysis and unit converiosn safety checked by the compiler instead of by hand is useful to anyone that does scientific computing. * Did you try to use the library? With what compiler? Did you have any problems? Yes. GCC 4.1.0 / Linux. No problems with any of the examples I compiled. I did not compile all of them, nor did I build the unit tests. * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? A quick look at the implementation (not all files), a thorough reading of the docs, and a bit of coding, based on the examples. * Are you knowledgeable about the problem domain? Yes. I've been using Andy Little's PQS library for years, and do a lot of physics-based programming in general. * Do you think the library should be accepted as a Boost library? In its present form, no. It pains me to say this, because I think the library is so good. If my concern about maintaining quantity invariance is addressed, I will happily change my no to a yes. I also would strongly like to see Imperial units supported out of the box, though that would not by itself be enough for me to vote no. Zach Laine

Hi Zach, Thanks for the review.
However, I have one strong objection. What is the rationale behind providing the mutating value() member function, and functions from_value() and quantity_cast() for converting raw scalar values into quantities? I really like the default rules on construction of
These were requested at various points in the development of the library; I completely agree with you that most of these shenanigans are undesirable. You will note that the mutating value() member function is not used anywhere in the test or example code - I'd be first in line to get rid of it, frankly.
of the quantity's class invariants. I want to be able to construct a set of quantities using their constructors, and thereafter be able to know, without checking through the code for abuses of value(), etc., that they and the results of any math done using them, are well-formed quantities. That is, I want Boost.Units to be hermetically sealed as much as is possible, so that I know that if I specify the units and values correctly at construction, I don't have to think about correctness after that. Mutable value() and quantity_cast(), and to a
Again, I agree. However, you can never get away from having to look for *_cast in your code if you want to be sure it is abomination free...
lesser extent from_value(), mean I have to work a lot harder (read: look in a lot more places) to ensure that my code is correct.
Specifically,
quantity<force> F(2.0*newton); quantity<length> dx(2.0*meter); F.value() = dx.value();
is an abomination and should be impossible. If I really want to do
Sure - I'm really happy to remove the mutating value() member function. The static from_value() member is not strictly necessary, but may be a reasonably compromise as it doesn't allow "abominations". It is also used in a number of places where we would have to use template friend declarations otherwise.
this, why not make me go through the constructor, so that attention is more obviously called to what I'm doing? I could also live with using
I think having a constructor directly take a value_type is the worst case scenario since it would make it very easy to neglect to specify a unit, thereby losing all type-safety gained by the intentionally redundant construction syntax...
a purposely ugly cast here, but since quantity_cast() has some perfectly legitimate and safe uses, I would much prefer a different syntax that draws attention to this unsafe act, such as quantity_reinterpret_cast().
I'm happy to do this or to restrict value_type construction to the from_value() member.
Why in the output of quantities are the negative exponents in parentheses? It seems a little odd that negative whole numbers do, and positive whole numbers do not.
No particular reason - it seems more readable to me, but I'm not wedded to it... At some point in the future, a more complete and mature system including localization and ability to control output format is on the agenda.
I and a lot of other users badly need support for Imperial units. As it stands now, we will each be required to write nearly identical code to do so. This should be included in the library.
The problem with these non-standard units is that they don't really form a well-defined unit system. FIrst off, there are Imperial units, US customary units, US survey units, nautical units, and English units - many of these have slightly variant definitions for base values. Because there is no specific standard for the base units (that is, what is the base unit of length in the Imperial system? inch? foot? yard? fathom? mile?), you would need to essentially have a distinct system tag for each unit, along with a whole slew of specializations for various conversions. There is an undocumented header file (boost/units/systems/other/non_si_units.hpp) that contains conversion factors for a wide range of non-SI units to SI. I realize that this is suboptimal for some applications, but I don't think it is possible to solve the problem of Imperial/English/US units in a clean way that will satisfy everyone. We have, however, supplied a number of examples of how to roll your own unit system...
You might want to reserve all system ordinal numbers below 1000 or 10000 for Boost.Units, instead of stopping at 100. There are plenty more numbers for users to choose from, and though 100 might sound like plenty now, you never know how many you might need.
Or maybe the ones from 1000 up?
to be desired. Specifically, do I need to assign any of these static constants an actual value? The macro does not do so. Why does the
The macro does not because it is used both for declaring static constant units (meter, second, etc...) that only have a default constructor and for static constant quantities that need to be assigned a value. Perhaps we need two macros for this instead?
example include singular and plural forms of the unit types ("meter" and "meters", etc.)?
Just for syntactic convenience - this way you don't have to remember if the definitions are singular or plural and it makes the code more literate if you read your equations : quantity<SI::length> q1(1.0*meter), q2(2.0*meters);
In example 1, it looks like you duplicated the first code block.
Actually not - L_T_type and V_type should be the same, so that's what we're testing...
Examples 14, 15, and 18 consist of a single line each. Was this intentional?
This documentation could be fleshed out more or the examples removed...
As mentioned in the TODO, there is no concept documentation. While this is not strictly necessary to use much of the library, it should at a minimum include concept requirements for quantity::value_type so that people can create their own Units-compatible types.
Yes - at some point I will do this. I just didn't want to put in a half-baked concept specification and would like it to be as minimal as possible so the requirements on value_type are correspondingly minimal...
* Do you think the library should be accepted as a Boost library?
In its present form, no. It pains me to say this, because I think the library is so good. If my concern about maintaining quantity invariance is addressed, I will happily change my no to a yes. I also would strongly like to see Imperial units supported out of the box, though that would not by itself be enough for me to vote no.
As I mentioned above, I'd be happy to eliminate the mutating value() member function. I am also not personally invested in the quantity_cast functions or their specific syntax. I would like to retain the static from_value() member function as I am virtually certain that there will be requests to enable some form of direct construction of quantities from a value_type. On the other hand, I wouldn't object to retaining some quantity_*_cast syntax and using that instead of from _value... Matthias

Zach Laine wrote:
Specifically,
quantity<force> F(2.0*newton); quantity<length> dx(2.0*meter); F.value() = dx.value();
is an abomination and should be impossible. If I really want to do this, why not make me go through the constructor, so that attention is more obviously called to what I'm doing? I could also live with using a purposely ugly cast here, but since quantity_cast() has some perfectly legitimate and safe uses, I would much prefer a different syntax that draws attention to this unsafe act, such as quantity_reinterpret_cast().
I agree completely with Zach's views on this. It's OK to have a const member function .value() but not a mutating one.
I and a lot of other users badly need support for Imperial units. As it stands now, we will each be required to write nearly identical code to do so. This should be included in the library.
Matthias Schabel wrote:
The problem with these non-standard units is that they don't really form a well-defined unit system. ... We have, however, supplied a number of examples of how to roll your own unit system... )
I agree with Zach and also want to be able to define units without having to "roll my own unit system".

The problem with these non-standard units is that they don't really form a well-defined unit system. ... We have, however, supplied a number of examples of how to roll your own unit system... )
I agree with Zach and also want to be able to define units without having to "roll my own unit system".
There is no way to avoid having some tag class to differentiate units having the same dimensional signature - it's just impossible to do it and preserve the ability to do zero-runtime overhead calculations. You don't have to define a system, but every unit needs to have a unique dimensional signature and a tag. Consider definition of the unit for gallon : struct imperial : public ordinal<1000> { }; typedef unit<volume_type,imperial> imperial_gallon; struct us : public ordinal<1001> { }; typedef unit<volume_type,us> us_gallon; The ordinal is necessary to be able to sort dimension lists and can't be gotten around because there's no way to have the compiler generate a unique enumerated sequence of values. It's hard to get much more concise than this... You can then define conversions between the two : /// convert imperial gallons to us gallons template<class Y> class conversion_helper< quantity<unit<volume_type,imperial>,Y>, quantity<unit<volume_type,us>,Y> > { public: typedef quantity<unit<volume_type,imperial>,Y> from_quantity_type; typedef quantity<unit<volume_type,us>,Y> to_quantity_type; static to_quantity_type convert(const from_quantity_type& source) { const typename from_quantity_type::value_type& in (source.value()); return to_quantity_type::from_value(in.value() *1.2009499255); } }; /// convert us gallons to imperial gallons template<class Y> class conversion_helper< quantity<unit<volume_type,us>,Y>, quantity<unit<volume_type,imperial>,Y> > { public: typedef quantity<unit<volume_type,us>,Y> from_quantity_type; typedef quantity<unit<volume_type,imperial>,Y> to_quantity_type; static to_quantity_type convert(const from_quantity_type& source) { const typename from_quantity_type::value_type& in (source.value()); return to_quantity_type::from_value(in.value()/ 1.2009499255); } }; That's all you need to do to define your own units. If you want them to be implicitly convertible, then you need to also define that : template<> struct is_implicitly_convertible<unit<volume_type,imperial>, unit<volume_type,us> > : public mpl_::true_ { }; template<> struct is_implicitly_convertible<unit<volume_type,us>, unit<volume_type,imperial> > : public mpl_::true_ { }; Matthias

On 3/26/07, John Phillips <phillips@delos.mps.ohio-state.edu> wrote:
The review for the Quantitative Units library, submitted by Matthias Schabel and Steven Watanabe begins today, March 26 and ends April 4.
• What is your evaluation of the design? I am really glad that this version of Boost.Units has limited its scope to purely compile-time. That's not to say that I wouldn't welcome a run-time version (I would!), but I think a narrow scope is essential to getting a units library into Boost. I have tried extending the library to use custom units and it's very easy to do. I do wish that there was no need to specialize base_unit_converter for conversions both ways when the second specialization is simply the reciprocal of the first. Steven posted a solution to this in a separate thread just now and I hope that it will get included in the final version. • What is your evaluation of the implementation? I know Matthias and Steven have put a lot of effort into making sure it's as efficient as possible, both in compile and run time. It looks very high quality. The following actually concerns design, implementation, and docs, so I wasn't sure where to put my comments: Example 16 looks strangely familiar! Glad to see it was interesting enough to make the examples. Concerning nautical miles: see http://en.wikipedia.org/wiki/Nautical_mile and http://www1.bipm.org/en/si/si_brochure/chapter4/table8.html. I'm not sure if this unit makes sense in the nautical namespace. One might ask "Why not boost::aerial?" The only reason I bring this up is because they are used for marine and aerial navigation. There may be other such examples, but I think all of the non_si_units.hpp units could reside in a boost::non_SI namespace with little confusion to the user. These would be all non-SI, but accepted, units (see http://en.wikipedia.org/wiki/Non-SI_units_accepted_for_use_with_SI). I also noticed that the unit knots was not defined in non_si_units.hpp. Is this an oversight? Why are some accepted non-SI units defined and others not? Is there an exhaustive list in the docs mentioning all units and their systems? • What is your evaluation of the documentation? I spent a lot of time using the docs as a user, not a reviewer. So far I don't have any major complaints. If I have time I will go back with a more critical eye and submit all design issues, typos, and grammatical errors in a separate e-mail, but for the most part they were very consistent with other Boost docs, and I found the examples quite helpful. I was able to extend the library with custom types very easily using the documentation provided. • What is your evaluation of the potential usefulness of the library? I think it will be extremely useful for users who want this type of safety with zero space and run-time penalty. I have already used earlier versions of this library in toy programs and prototypes with much success. These include GUIs where the user chooses what unit to provide his input in, and output to a visualization layer. • Did you try to use the library? With what compiler? Did you have any problems? Yes, VS 7.1 and VS 8.0. No problems to report. • How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? I have been using this library in various stages of its development in prototypes and toy applications. Part of that required delving into the source to figure out compile errors I was having early on, and part of that required extending the library to use custom types. I spent a total of about 4 hours using the review version of the library, but weeks of use with previous versions. • Are you knowledgeable about the problem domain? Not especially. The programs I work on are mostly GIS related, and rarely deal with physics, fluid dynamics, or things of that nature. The applications I deal with get values from databases that store things like radar characteristics, aircraft performance metrics, and terrain and elevation data. None of them use a unified unit system, so the existing legacy code is rife with conversions. I've encountered two bugs so far where meters were being compared to feet, and I'd like to turn bugs like that into compile-time errors. • Do you think the library should be accepted as a Boost library? Yes, certainly. I would, however, like to hear Matthias' and Steven's thoughts on how easy it would be to add a run-time layer on top of their existing work. Thanks for all your hard work. --Michael Fawcett

Michael, Michael, Thanks for your positive review. I'm glad that the library is working for you in a practical setting - that's always a concern for us academics divorced from the real world ;^)
specialization is simply the reciprocal of the first. Steven posted a solution to this in a separate thread just now and I hope that it will get included in the final version.
This should not be a problem; I'm accumulating a list of changes to be made as they come in.
Example 16 looks strangely familiar! Glad to see it was interesting enough to make the examples.
Your example was actually the impetus driving the decision to implement heterogeneous units, a project that I know Steven spent a significant amount of time and effort to get right...
sure if this unit makes sense in the nautical namespace. One might ask "Why not boost::aerial?" The only reason I bring this up is because they are used for marine and aerial navigation. There may be
I tend to try to name things so they sound right if you read them; even though they are used in aerial navigation, as far as I understand they are still called nautical miles, so to my eye nautical::miles reads right.
other such examples, but I think all of the non_si_units.hpp units could reside in a boost::non_SI namespace with little confusion to the user. These would be all non-SI, but accepted, units (see http://en.wikipedia.org/wiki/Non-SI_units_accepted_for_use_with_SI).
This is probably one of the darker corners left in the library; I'm hoping that reviewer input will help to shape the final form of the non-SI portion of the library. Steven has some ideas for dealing with the irregularities of US/Imperial units in a relatively clean and elegant way. However, putting all of these into the same namespace is problematic because there are, for example, differing definitions of units having the same name (mile, in particular) so us_customary, us_survey, and nautical miles are all slightly discrepant.
I also noticed that the unit knots was not defined in non_si_units.hpp. Is this an oversight? Why are some accepted non-SI units defined and others not?
I just have very limited personal experience with and use for these traditional units, so I didn't think to add it. I'm certainly happy to put knots in. I don't believe they were listed in the NIST documents I was referencing. Because there are so many irregular units out there, I'm reluctant to promise to support everything under the sun in the library, but the decision of where to stop is a bit arbitrary. I just used the NIST document as my yardstick (sorry...)
Is there an exhaustive list in the docs mentioning all units and their systems?
There is not yet, but should be.
Yes, certainly. I would, however, like to hear Matthias' and Steven's thoughts on how easy it would be to add a run-time layer on top of their existing work.
A runtime component would be essentially a parallel library that replicated the existing dimensional analysis functionality in runtime code. I've mentioned previously that it would be relatively easy to specialize to get a syntax like quantity<arbitrary,Y> that looks much the same as the existing syntax. It probably wouldn't be hard to implement runtime algorithms; I am still extremely skeptical that there are many users out there who would be willing to pay the computational cost and memory overhead of doing all of the dimensional analysis at runtime. At a bare minimum, I would like to see some "real" use cases where it isn't possible to get reasonable behavior with the existing library. As you mention, the current implementation works fine with GUIs as long as you're willing to pick an internal representation for the units used at compile time. There would also need to be compile-time -> runtime conversions, input parsing, etc... which would involve varying degrees of effort - the latter probably will be hardest... Matthias

On 3/28/07, Matthias Schabel <boost@schabel-family.org> wrote:
I tend to try to name things so they sound right if you read them; even though they are used in aerial navigation, as far as I understand they are still called nautical miles, so to my eye nautical::miles reads right.
This isn't a big issue to me, but it does seem inconsistent. Yes, the unit is called "nautical miles", but would you also propose that "US survey foot" be US::survey::foot? The precedent you seem to have set with the other unit systems is system::unit. I think nautical::miles is inconsistent. --Michael Fawcett

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Michael Fawcett Sent: 30 March 2007 15:36 To: boost@lists.boost.org Subject: Re: [boost] [Review] Quantitative Units library review begins today,March 26
On 3/28/07, Matthias Schabel <boost@schabel-family.org> wrote:
I tend to try to name things so they sound right if you read them; even though they are used in aerial navigation, as far as I understand they are still called nautical miles, so to my eye nautical::miles reads right.
This isn't a big issue to me, but it does seem inconsistent. Yes, the unit is called "nautical miles", but would you also propose that "US survey foot" be US::survey::foot?
Surely it should be US::survey::feet ;-)) which I feel is a sort of reductio ad absurdum argument http://en.wikipedia.org/wiki/Reductio_ad_absurdum for keeping everything singular? Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

On 3/30/07, Paul A Bristow <pbristow@hetp.u-net.com> wrote:
Surely it should be US::survey::feet ;-)) which I feel is a sort of reductio ad absurdum argument http://en.wikipedia.org/wiki/Reductio_ad_absurdum for keeping everything singular?
:) I'm kind of ambivalent to the singular/plural/spelling issues. The main thing I object to is breaking apart a unit name. Maybe a better example would be tower pound. IMHO that should not be tower::pound (it should be English::tower_pound), so nor should nautical miles be nautical::miles. Maybe SI::accepted::nautical_miles, or just SI::nautical_miles? --Michael Fawcett

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of John Phillips Sent: 26 March 2007 12:55 To: boost@lists.boost.org Cc: boost-users@lists.boost.org Subject: [boost] [Review] Quantitative Units library review
The review for the Quantitative Units library, submitted by Matthias Schabel and Steven Watanabe.
What is your evaluation of the design? Correctly, IMO, emphasises compile-time checking (with next to no run-time cost) over run-time conversions. (Run-time is superficially attractive but loss of precision creates plenty of pits for the novice to fall into, not to mention the run-time cost. Slow and dirty?). Handles non-integral power dimensions well enough. Correctly IMO does not try to handle input-output (except very simple output). (Its takeup with will be increased by more examples of doing this - even though individual requirements will vary widely, examples of 'fiddling with facets' will be a great help. Capable of handling a wide variety of different unit systems, including astronomical units. Correctly, IMO, "this library is designed to emphasize safety above convenience". Default is to enforce explicit conversion - but makes it possible for implicit conversion if the user wants to take the risk - a reasonable compromise. Inter-operation with other Boost libraries like serialization and interval is a good sign. Handles the deceptively complex temperature conversions effectively. What is your evaluation of the implementation? Effective. Sufficiently portable - older compilers cannot ever provide a solution to this problem. Been developed and supported over a long enough time to give confidence of future support and development. Fast enough with current hardware and compiler software to make the added security against mistakes worth the cost of increased compile time. (Nobody has used it on an industrial strength (size) project to say if this is a startup cost that does not increase compile time so much for big projects - but I too believe this will prove to be so.) What is your evaluation of the documentation? Boost quality - and that's a compliment, not damning with faint praise ;-) - but of course it can always be improved - and I trust will be in the light of user experience. A very useful set of examples, but the very many responses to users questions could very usefully be added as additional examples of very many more applications, like currency and other conversions etc. A lot of naïve users will be using this library (I hope) and they will need all the help they can get. What is your evaluation of the potential usefulness of the library? Very widely useful - if more trouble than some will wish to get started. (I see no way of reducing the learning curve steepness and hassle factor in use in the language C++ - it is already using state of the art MPL and will work better with C++0X 'typeof'. And, AFAIK, it achieves far more than any other language in both units and dimension checking.) Although serious scientists and engineers are the obvious customers, very many programming tasks involve some measurements, often done by programmers whose experience is mainly in more integral objects. So I see the potential for *very* wide application. And because its primary objective is compile-time checking, with considerable complexity, and some compiling-time cost, some may decide not to use it. This is not a reason not to include it as a Boost library. Did you try to use the library? Yes, briefly, with VS 2007 compiler. Did you have any problems? No. How much effort did you put into your evaluation? Re-study of the documentation after following the (very!) long Boosters debates. Brief test of a few examples. Are you knowledgeable about the problem domain? Slightly. But I have followed all the discussion and proposals on this topic. Do you think the library should be accepted as a Boost library? Yes - definitely. We have waited far too long for a 'perfect' solution to these difficult problems: it does not exist. The Best is the Enemy of the Good. It seems obvious that we can't please all the people all the time, but this design and implementation makes a good compromise between conflicting potential users, potential use domains, and offers enough extension potential to other more esoteric and frankly bizarre unit systems, if at the cost of making even expert programmers brains hurt a bit. Although I was in favour of accepting Andy Little's PQS into Boost, I remained uneasy about it for reasons I could not fully articulate: I am much more comfortable with the balance of pros and cons of this submission. We now need some real users to use this code in 'real anger': if it survives this, it will be truly proven. We won't, IMO, get much, if any, large-scale use until it is accepted into Boost. Paul PS Nit noted en passant: Quick start spelling mistakes: "of using user-defined types in dimensional calcuations," and /// test calcuation of work - should be calculation, twice. One of my favorite spilling misfakes ;-) --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Paul A Bristow Sent: Friday, March 30, 2007 5:11 AM To: boost@lists.boost.org Subject: Re: [boost] [Review] Quantitative Units library review begins today,March 26
...
Handles the deceptively complex temperature conversions effectively.
When I asked this question, I was only pointed to an example. Where is temperature conversions handled within the library? Eric.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Eric Lemings Sent: 30 March 2007 16:08 To: boost@lists.boost.org Subject: Re: [boost] [Review] Quantitative Units library review begins today,March 26
Handles the deceptively complex temperature conversions effectively.
When I asked this question, I was only pointed to an example. Where is temperature conversions handled within the library?
I said that examples from the discussions need to be added... But anyway I think that any sane program will confine itself to one temperture scale internally. Is anyone still using the antediluvian Farenheit? (rods poles perches, gallons, barrel... ;-) Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

Paul, Thanks for your vote.
will be in the light of user experience. A very useful set of examples, but the very many responses to users questions could very usefully be added as additional examples of very many more applications, like currency and other conversions etc. A lot of naïve users will be using this library (I hope) and they will need all the help they can get.
We're happy to assist prospective users in addressing their issues. As you observe, this library is not trivial (a reflection that the area it addresses is much less straightforward than many people imagine - as I did before really examining the subtleties). We have tried to make it easy to use for simple use cases, but implementation of custom unit systems, conversions, etc.. requires some understanding of the implementation.
the art MPL and will work better with C++0X 'typeof'. And, AFAIK, it achieves far more than any other language in both units and
C++0X auto and typeof will dramatically ease definition of new units and quantities...
Quick start spelling mistakes: "of using user-defined types in dimensional calcuations," and /// test calcuation of work
- should be calculation, twice. One of my favorite spilling misfakes ;-)
The downside to touch typing is when your kinetic memory gets programmed incorrectly, it becomes really easy to quickly type specific misspellings - thanks for noting this. Matthias

This review comes a bit late, because I'm really short on time this week and I still wanted to study the library as close as possible. I plan incorporate units into a fairly big project (http://yade.berlios.de/ it's big: over 15000 lines). Before I do so I need to check if it fulfils my requirements. (a) must work with Vector3 and allow working with (dimensionless) Quaternions (inflicting rotation (radians/degrees <-> quaternions) and calculating momentum [N/m] (b) must allow GUI input with unit selection by the user (predefined dimensions) (c) the docs must be good enough for me to find the answer quickly The (a) requirement is satisfied as can be seen in the the examples, so due to lack of time I didn't bother to check that in-depth. The (b) caused tons of discussions and, if I'm correct, a negative vote from Noah Roberts. I had no time to read carefully that discussion thread to be 100% sure that my requirement is exactly the same as the issue raised there. I've written a short program to see if it's possible to make. And surprisingly it was very easy and intuitive to write. Perhaps the library authors will want to include this into their examples. The attached screenshot and the attached sources should make my intentional usage clear. See section 5 below for detailed discussion. Correct me, if that is not what Noah requested. The most relevant code is in the attached calculatorform.cpp file. Other files are created by qt4. The (c) is answered in section 3. Bottom line: good design solved the problem of lacking documentation. (not much need to look at docs if everything is intuitive) 1. What is your evaluation of the design? ================================================= Very intuitive. Much more intuitive than most of the other libraries that are currently in boost. Maybe because as a C++ programmer and an engineer I know how units should work - and the interface presented was nearly as I would expect it to be. I've run into this library at full speed and I didn't bump into any wall of misunderstandings. Since I wanted to write my testing (b) program as quick as possible it was close to the "real anger" test, and the outcome was positive. The good design was the major factor that helped with that. With good design I didn't need to spend unnecessary minutes to search for an answer in the documentation. 2. What is your evaluation of the implementation? ================================================= My general impression is that the implementation is close to optimal in terms of template design. I looked at the sources rather briefly, so I won't comment about implementation details. I can only speak about the "outside impression". My only complaint is about lengthy typenames. Like for example my Newton's Law function (attached calculatorform.cpp:65): quantity<SI::force> newtons_law(const quantity<SI::mass>& m, const quantity<SI::acceleration>& a) { return m*a; } I'd prefer a shorter variant: force newtons_law(const mass& m, const acceleration& a) { return m*a; } Of course I can make a typedef. But the name "force" is already occupied. Using name "force_type" (as proposed in the examples) is a bit inconsistent, because the SI::force is a type too. And "force_type" is longer, which I don't like ;) That's just a small usage glitch, and I'm 100% sure that it can be solved this way or another. As it's just about naming. If the library remains unaltered I'll simply make some short typedefs and use them thorough 15000 lines of my code ;) A good practice BTW. PLURALS As mentioned in other posts the ISO 31-0:1992 tells that unit names should not be plural. I was unable however to see the ISO standard itself (google only brings up the webpages where I can *buy* the ISO standard), but I have found an ISO faq about that: http://lamar.colostate.edu/~hillger/faq.html#spelling-names and (search the text for "plural"): http://www.unece.org/trade/untdid/download/r1224.txt (I think that "unaltered in plural" means that they have no plural) I (like others) think that users will prefer to have less options and use whatever the library authors will decide. Therefore I suggest to drop the plurals. ISO standard however applies only to SI units, other systems, because they are non-standard, may need to use plural ("feet" being an outstanding example). Therefore I leave that issue up to the authors. 3. What is your evaluation of the documentation? ================================================= Documentation is a bit lacking. But in fact I didn't want to spend much time reading it. I wanted to quickly go into 'coding mode' - so that was a kind of "real anger" test. And the library was coded so intuitively with attached examples so complete, that I rarely needed to look into documentation. However when I had to look there I noted following things: "Example 14" : I suggest to put there at least the program's output there. Same with Example 15 and 18. The "base_unit_converter<>" in Example 16 should be hyperlinked to the explanations what it is and how to use it. And similarly all the other keywords related with the library. People like me in "real anger" spend most of the time looking at examples. Therefore examples should be heavily hyperlinked to the rest of the documentation, so that every keyword has explanation under a single mouse click. Documentation should have a FULL list of all predefined units, so it will be a quick reference for the users. 4. What is your evaluation of the potential usefulness of the library? ================================================= Huge potential. In the past I've spent countless hours looking for an error that such library would help to avoid in the first place. Very useful. 5. Did you try to use the library? With what compiler? Did you have any problems? ================================================= COMPILERS I urge the authors to add some basic compiler-checking and emit an #error when an unsupported compiler is used. Due to lack of time I did not investigate why tutorial.cpp did fail on: gcc version 3.3.5 (Debian 1:3.3.5-13) (sarge), but instead I quickly switched to: gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) (etch) Perhaps it was my fault. But IMHO not: g++ 3.3.5 is very old and I'd be surprised if it worked. So some #error (or a #warning at least) from the library would be nice to make it clear for the people. EXAMPLES Speed "Example 14": With debug information and no optimizations: f(x,y,z) took 8.04 seconds with double f(x,y,z) took 108.64 seconds with quantity<double> g(x,y,z) took 8 seconds with double g(x,y,z) took 91.07 seconds with quantity<double> With full optimization g++-4.1 -O3: f(x,y,z) took 2.71 seconds with double f(x,y,z) took 2.7 seconds with quantity<double> g(x,y,z) took 2.72 seconds with double g(x,y,z) took 2.7 seconds with quantity<double> Surprise: with units it's faster! How could that be possible? Perhaps a measurement error. I increased REPETITIONS tenfold: f(x,y,z) took 28.11 seconds with double f(x,y,z) took 28.12 seconds with quantity<double> g(x,y,z) took 30.3 seconds with double g(x,y,z) took 28.13 seconds with quantity<double> Well, I don't get it. But I like it. I thought that AMD processor may cache something and the second invocation of f() is faster so I changed the order of function calls: f(x,y,z) took 27.08 seconds to run 1e+10 iterations with quantity<double> = 1.4771e+09 flops f(x,y,z) took 29.18 seconds to run 1e+10 iterations with double = 1.3708e+09 flops g(x,y,z) took 27.09 seconds to run 1e+10 iterations with quantity<double> = 1.47656e+09 flops g(x,y,z) took 29.18 seconds to run 1e+10 iterations with double = 1.3708e+09 flops With units it is faster by two seconds. I ran the test several times, and read the code few times. Maybe executable with "slower" units is accidentally better synchronized with memory access frequency MHz. Congratulations, you beat me. Those results were obtained with: gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) THE GUI INPUT UNITS TEST This short QT4 program in the attachment was my only experience with this library, and a very positive one. (apart from compiling attached library examples) If you want to compile it, you need qt4 installed, then you can run (linux, mac, windows): qmake make and you should get an executable. The part most relevant to proposed units library is in calculatorform.cpp file. I have created a dropdown menu (QWidget::ComboBox) where the user can pick the desired unit of the input. Each item in this drop down menu is given a conversion factor. In current implementation only few conversion factors are present and they are hardcoded. However in the real world scenario the conversion factors will be put in some array, and will be configurable by the user from the software's GUI (like File->Preferences). This would make the attached example shorter by few lines, and looking much more clean. By writing this example I am absolutely sure that it is simple to make a customized unit input. And the reader should be convinced too, after a short look at the attached .cpp file. The design decision of the library authors to skip the unit input, was the best possible. Because otherwise the library would have to support everything possible: qt4, wxwidgets, gtk, winapi, iostreams, etc.... That would be crazy :) Better provide right tools, and the user (me) does the work he needs, like in the attached code. However I encountered a small glitch there. I couldn't obtain a conversion factor from simple units division, which is surprising (calculatorform.cpp:36) force_unit_box->addItem("dyne", 1.0*CGS::dyne/SI::newton ); dividing '1 dyne' by '1 newton' produces a dimensionless double value that should contain the conversion factor, but instead it wrongly produces "1.0". Finally I had to hardcode the conversion factor. I also tried to look for base_unit_converter<> but there wasn't any defined for force, and I wouldn't like this solution at all. I expect that this issue will be resolved before adding the library into boost. The best solution is to allow implicit conversion from dimensionless type to underlying type (double), as in calculatorform.cpp:47. 6. How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? ================================================= It was two evenings, about 6 hours each. Would give 12 hours total. Much more than quick reading. But not an in-depth study. 7. Are you knowledgeable about the problem domain? ================================================= Yes, I've written a PhD in civil engineering, and I'm programming in C++ for 10+ years. 8. Do you think the library should be accepted as a Boost library? ================================================= Yes it should be accepted. Before adding to CVS-HEAD please do following: 1. support calculations of conversion factors as explained above. Attached file calculatorform.cpp:47 (or convince me that I'm wrong, but hey - how to do it more conveniently than in this way?) 2. check for compiler used and emit an #error when unsupported compiler is detected. So that users won't waste time on futile fights with their compilers. -- Janek Kozicki |

Janek, Thanks for the thorough review and comments and thanks for your positive vote.
was very easy and intuitive to write. Perhaps the library authors will want to include this into their examples. The attached screenshot and the attached sources should make my intentional usage clear. See section 5 below for detailed discussion. Correct me, if that is not what Noah requested. The most relevant code is in the attached calculatorform.cpp file. Other files are created by qt4.
Yes, I will see about incorporating this into our examples - it's a good demonstration of interfacing with a GUI...
Very intuitive. Much more intuitive than most of the other libraries that are currently in boost. Maybe because as a C++ programmer and an engineer I know how units should work - and the interface presented was nearly as I would expect it to be. I've run into this library at full speed and I didn't bump into any wall of misunderstandings.
I'm really glad to hear this - as a physicist, I want this library to behave according to the principle of least surprise as much as it is possible for it to do so within the constraints of the C++ language. If you do run into counterintuitive behavior, please let us know so we can rectify it.
My only complaint is about lengthy typenames. Like for example my Newton's Law function (attached calculatorform.cpp:65):
Yes, names can be long, but I don't think there's any easy way to avoid this without making use of the library less intuitive. Certainly for many, if not most, projects, only a relatively small set of quantities will be used and, as you note, those can be typedef'd...
I (like others) think that users will prefer to have less options and use whatever the library authors will decide. Therefore I suggest to drop the plurals.
We're happy to do this; there is a minor problem with the SI unit of pressure : pascal is defined by MSVC in a way that appears difficult to circumvent, so that would have to be pascals...
Documentation should have a FULL list of all predefined units, so it will be a quick reference for the users.
Yes, once we've settled on a set of officially supported units, we'll make sure to have a comprehensive reference section on them.
I urge the authors to add some basic compiler-checking and emit an #error when an unsupported compiler is used. Due to lack of time I
Good point - it will not work on gcc prior to 3.4.4 or MSVC below 7.1. We haven't tested other compilers other than Metrowerks yet...
Speed "Example 14":
With units it is faster by two seconds. I ran the test several times, and read the code few times. Maybe executable with "slower" units is accidentally better synchronized with memory access frequency MHz. Congratulations, you beat me.
Well, as has been pointed out, it's hard to do performance comparisons well. Steven put together a significantly better test case using ublas...
The design decision of the library authors to skip the unit input, was the best possible. Because otherwise the library would have to support everything possible: qt4, wxwidgets, gtk, winapi, iostreams, etc.... That would be crazy :) Better provide right tools, and the user (me) does the work he needs, like in the attached code.
It's great to hear that this works for you in this type of application. I'll have to give it a try.
However I encountered a small glitch there. I couldn't obtain a conversion factor from simple units division, which is surprising (calculatorform.cpp:36)
force_unit_box->addItem("dyne", 1.0*CGS::dyne/SI::newton );
dividing '1 dyne' by '1 newton' produces a dimensionless double value that should contain the conversion factor, but instead it wrongly produces "1.0". Finally I had to hardcode the conversion factor.
I would regard this as a bug - it should, as you expected, reduce to the conversion factor. This actually raises a surprisingly sticky issue : what to do with a dimensionless quantity where the conversions are not all defined? By definition, dimensionless quantities are implicitly convertible to their value_type. Probably the best thing to do is for it to be a compile error to instantiate a dimensionless quantity that is not reducible to a scalar...
I expect that this issue will be resolved before adding the library into boost. The best solution is to allow implicit conversion from dimensionless type to underlying type (double), as in calculatorform.cpp:47.
This is how it should work. We'll get this bug worked out... Thanks again. Matthias
participants (8)
-
Deane Yang
-
Eric Lemings
-
Janek Kozicki
-
John Phillips
-
Matthias Schabel
-
Michael Fawcett
-
Paul A Bristow
-
Zach Laine