Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2004-10-24 07:53:51


>From: "Andy Little" andy_at_[hidden]

> "Terje Slettebø" <tslettebo_at_[hidden]> wrote in message
>
> > I've been playing with a library like this, a year or so ago, too, but
saw
> > there were several proposals in that area, which worked similarly, and
> > decided instead to focus on the Concept Traits library. I decided that I
> > could then instead support other people's proposals in the area of
> > quantity/units library.
> >
> > I've always seen this kind of library as a "fun" thing, :) as I'm
> interested
> > in science, having "played with" electronics, physics, chemistry, etc.
> > especially in my youth, and I'm sure such a library - of Boost standard
> > (using modern C++), which this one seems to be - would be a great thing
> for
> > scientists, and people interested in science, everywhere.

Some of the issues I ran into, when playing with such a library, were:

How to handle input/output, especially formatting the prefix and unit
information. For example, one may write the same unit as:

1 MJ
1000 kJ
1000000 J
1 megajoule
10^6 J
10^6 kg·m^2·s^-2
10^6 kg·m^2/s^2
etc.

In other words, it may be written in an infinite variety of forms. Moreover,
the user may want the various forms in different contexts. Thus, I/O was one
of the areas I found most complex to solve. The unit calculation itself is
really a solved problem. :) (at least for the usual SI units).

Because of this, it may be best to decouple the presentation from the unit
calculation. One may provide some convenience output components, but it may
be best if it's also possible for the user to provide the formatting in any
way they want. For example if they want to show it using a GUI widget. So
one may have functions to retrieve the components of the quantity, i.e. the
numerical value, the unit (or unit components in the fundamental SI units)
and their exponent, etc.

If one provide convenience functions, then there's an issue of if one should
provide names for both char and wchar_t, and how to deal with output of
units that have no ASCII/Latin1 character, such as ohm.

Looking at the docs, it seems that this issue has been considered, and that
it's possible to provide custom output. Could you perhaps have shown how to
output some of the formats above, given the quantity 1 MJ?

I've mentioned SI, here. That should be an "alarm bell", because another
issue to consider is if the library should be SI specific, or be able to
handle units in general, including user-supplied ones. I remember this has
been discussed in earlier discussions about quantity libraries, here, and
one "obvious" candidate for non-physical units is money: You may have a
numerical value, and its currency, and the possibility to convert between
the various currencies.

Your library is named "physical quantities library", and this points to it
being more SI-specific; looking at the implementation, it seems the number
of dimensions is hardcoded to 9. I'm not saying this is right or wrong,
merely mentioning that - apart from the I/O issue - this was another major
headache I had in the design of the library I worked on. The headache was
this: It would be possible to accommodate for an arbitrary number of
dimensions (for example using typelists or type vectors - see Dave Abraham
and Aleksey Gurtovoy's article "A Deeper Look at Metafunctions"
(http://www.artima.com/cppsource/metafunctions.html) for an example of this.
I used a similar approach, but without the mpl::transform part, as my early
version was Loki-based (I had a custom "transformer"). Had I done it today,
I'd use MPL), but then one question is what the cost may be in terms of
compilation time. Using type vectors rather than typelists might be faster,
but necessarily; I tried to substitute mpl::vector for mpl::list in the
Concept Traits library unit test, and watched the compilation time go
through the roof...

On the other hand, if one stick to a fixed number of dimensions, how many is
enough? And what should they be?

If we were to get a quantity library in Boost, I think it should be able to
handle other quantities than the physical ones, as well (I didn't think of
the money example in the previous post, so I couldn't think of a
non-physical quantity example, but I was concerned about the library being
SI-specific. As I said above, this might be ok, but should be something that
should be explicitly addressed, perhaps in the FAQ).

One sticky issue if you allow arbitrary units/dimensions, is that in SI, the
only base unit with an exponent is "kg" (due to "historical accident), so
1000 kg isn't 1 kkg but 1 Mg. This has to be accommodated.

Because of issues like this (particularly the compile time/flexibility
concern), and seeing that there were several other approaches in existence
for this, I was content to step aside, and watch them struggle with these
issues, instead. :)

Just something to chew on. :) It's probably nothing new, but I think these
are issues that needs to be addressed for a library to be considered for
Boost.

> The 'fun' thing is a key point of the library. Another useful feature is
> consistency in converting between units, as well as the fact that each
type
> encodes a lot more information than a double, making it a C++ 'hub' for
> conversion to-from eg XML , or the same entity in other programming
> languages, data exchange , COM, CORBA etc. (Thats a theme I would like to
> pursue in other areas such as graphics too) I hope to get to get to grips
> with the serialisation library when the next boost distro comes out and
try
> to implement some of this.

I guess this addresses the I/O, also.

> The other aspect is simply that of modelling. It
> helps to visualise the entity you are modelling when the physical
quantities
> are named. That is difficult to describe rationally but certainly helps me
> when I am coding. The fun aspect translates into much better understanding
> of what source code is actually doing.

Absolutely. When I played with my library, it was rather fun to write, e.g.
(to use the syntax in your library):

length::m m=123;
mass::kg kg=234;
time::s s=10;

std::cout << kg*m*m/(s*s);

and get the output:

35.40186 kJ

:)

In other words, it told you what the named unit was, if it existed. The
output was done by having some stream state decide the formatting. However,
as mentioned, this was rather experimental: I ended up using a formatting
string, for more or less maximum flexibility, i.e. "%v %p%u<n>", where <n>
was a number from 0 and up. 1 would give the output in the base units
("kg·m^2·s^-2"); 2 would give the next "level" up ("N·m"), and 3 would give
the level after that (if existed) "J". %v gives the numerical value
(excluding the prefix value), "%p" gives the prefix - "k" here, and "%u"
gave the unit, "J". I had "tons" of these format specifiers, so I could get
"35.40186 kilojoule", etc., as well.

To sidestep this "implicit"/stream-stored formatting, it might be better to
use casting, as you use in the library, provided that you can then print the
resulting quantity any way you want.

Oh, and one other thing to consider: The handling of temperature. For
example, will you be able to accommodate different temperature scales?:

temperature::K t=283.15;

std::cout << (temperature::C) t; // Prints "10 °C", or some such.

Note that for Fahrenheit, it's not just an offset calculation, but also the
degrees are different.

Some of this stuff is what makes making a quantity library both challenging
and fun. ;)

(Like I said in the previous posting, you're talking with someone who have
struggled with these issues, so I guess I have some idea of some of the
thorny issues it may raise. ;) )

> > I tried to test the library on Intel C++ 7.1 (electronics_example.cpp,
> > picked at random) but got some errors which prevented the test, so I've
> > tried it on g++ 3.2, instead, where it worked. Unless I haven't found
it,
> > you might want to include which compilers/versions it works for in the
> docs.
> > If you're interested in the diagnostics from Intel C++, I can mail them
to
> > you.
>
> Yes I would be very interested in that naturally, maybe a boost post would
> be most useful?

There are many of the same kind, so sure:

Several of each of these:

electronics_example.cpp
PQS-2-00-02\pqs/numeric/converter_exception.hpp(24): warning #811: exception
specification for implicitly declared virtual function
"boost::numeric::bad_numeric_conversion::~bad_numeric_conversion" is
incompatible with that of overridden function "std::bad_cast::~bad_cast"
      class bad_numeric_conversion : public std::bad_cast
            ^

PQS-2-00-02\pqs/meta/rational_c.hpp(84): error: the type of partial
specialization template parameter constant "N" depends on another template
parameter
          IntegerType N,
                      ^

PQS-2-00-02\pqs/ct_quantity/named_abstract_quantity/anonymous_abstract_quant
ity/length_pwr.hpp(76): error: constant "N2" is not used in template
argument list of class template
"pqs::meta::binary_operation<pqs::length_pwr<N1, D1>, Op,
 pqs::meta::rational_c<RatValueType, N2, D2>, void>"
          int N2,
              ^

Then this:

E:\PROGRAM\C++\PQS-2-00-02\pqs/ct_quantity/named_abstract_quantity/anonymous
_abstract_quantity/length_pwr.hpp(66): error: class "boost::mpl::void_" has
no member "numerator"
              base_type::numerator,
                         ^
          detected during:
<long instantiation stack trace snipped>

Then some smaller stuff:

PQS-2-00-02\pqs/ct_quantity/ct_quantity.hpp(116): remark #424: extra ";"
ignored
          };
           ^

Several of these:

PQS-2-00-02\pqs/ct_quantity/quantity_unit/si_prefix.hpp(65): warning #1334:
the "template" keyword used for syntactic disambiguation may only be used
within a template
      si_unit::prefix<si_unit::yotta>::template symbol<char>()
                                       ^

I'll send you the whole thing on mail, as well.

Note that although Intel C++ is EDG-based, the Windows version (which I
used) is a little "schizophrenic", as it tries to be "compatible" with MSVC,
too, especially if you play with some of the (undocumented, for Intel C++)
EDG switches, to try to make it more conformant. I used the following:

--arg_dep_lookup
--no_microsoft_bugs
--no_guiding_decls

However, even when not using any of these switches, it gives the above
errors. As EDG (which Intel C++ uses) is considered one of the most
conforming compilers there is, I think it makes sense to at least compile on
an EDG compiler, too.

> It has only been tested on VC7.1 and gcc3.2.( As I
> understand it the base level for a boost proposal is two compilers)

I haven't seen that explicitly, but my experience is that for more regular
stuff, two compilers might be enough, for more tricky/advanced stuff, one
should test on at least three. The Concept Traits library compiled and ran
fine on Intel C++ 7.1 and MSVC 7.1, but bombed on g++ 3.2, so even if it
works on two compilers, that's no guarantee for the third (even for the
first two, having developed it on Intel C++, I had to tweak it a little to
make it work on MSVC 7.1).

> > What might help is to give an overview of other libraries that exist for
> > this, and what makes PQS different. One place to look is the Boost Files
> > section (I saw at least three such libraries there).
>
> This is a tricky area, as I have already spent considerable time
criticising
> other units libraries.

Unless I've missed it, maybe this could have been included in a section in
the docs, too? This gives other people an overview of how your library
stands in comparison to these other proposals, maybe as well as the
rationale for the choices. I realise this can be quite a lot of work (and as
you said, you've done a lot of work in this area, already, although perhaps
not documented it to a large degree), but as a library author, if you want
to "sell" your library, I'm afraid you'll have to do this, too, just like
salespeople need to be aware of the competition (if any), and be able to
explain what makes their product better, to make a successful sale. :)

Regards,

Terje


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