Boost logo

Boost :

From: Leland Brown (lelandbrown_at_[hidden])
Date: 2006-07-01 06:05:50


Andy Little <andy <at> servocomm.freeserve.co.uk> writes:
> "Beth Jacobson" wrote
> > Andy Little wrote:
> >> In PQS the units are part of the type. IOW the numeric value and
> >> its unit are always tightly coupled in code. That is a powerful
> >> feature. Once the numeric part of a quantity is disassociated
> >> from its unit then manual checking and external documentation is
> >> required, which is often the current situation wherever doubles
> >> are used to represent quantities. Manual checking doesnt always
> >> work as well as intended... That of course is why the Mars lander
> >> crashed!

Agreed! Any code containing a numeric literal for a physical quanity,
or any code that inserts or extracts a numeric value from a quantity
should be required to also specify the units of the numeric value.
That's a critical part of the goal of the PQS library.

> > I agree that unit checking can be an extremely useful feature, I'm
> > just not convinced that tight coupling is necessary to achieve
> > that.

But I also agree here. The goal can be achieved without necessarily
making the units part of the type. I'll explain.

> There is planned another quantity where you can change the units at
> runtime FWIW.

I mentioned much earlier that my own implementation of a quantities
library was more like the so-called "t2_quantity" - at least the way I
envisioned the t2_quantity. But as I read the discussion it occurs to
me that my idea may not be the same as yours, and it might be useful
for me to share what I have in mind. I hope it will shed some more
light on the "length::m vs. length" debate.

A couple of people have suggested a syntax more like this:

    length d = 5 * meter;
    speed v = 2 * inch / second;
    time t = d / v;
    cout << "time = " << t / minute << "minutes";

I also like this usage - this is how my library works. As you've
pointed out, Andy, this is trivial to achieve with the current PQS
implementation, by using:

    typedef pqs::length::m length;
    typedef pqs::time::s time;
    typedef pqs::velocity::m_per_s speed;

    const length meter(1);
    const length inch(0.0254);
    const time second(1);
    const time minute(60);

The problem is, it also allows sloppy code like this:

    length d(5); // no error; but units not clearly documented!
    speed v(2); // no error; but units not clearly documented!

so that the numeric values are now divorced from their units (which
are defined above, in the typedefs), thus potentially leading to
another Mars lander problem. What I want is the syntax I illustrated
but to enforce specifying units along with numeric values.

It occurs to me that perhaps this would work:

    struct length : public pqs::length::m
    {
        length( pqs::length::m x )
            : pqs::length::m( x ) { }
        operator=( pqs::length::m rhs );
    }

etc. I don't think this is a big departure from the current PQS
concept. It's just a simple extension, really, but I think a very
helpful one. As a user I'd rather have something like this provided
for me than to have to write the extension myself for each type -
length, time, speed, energy, etc.

The cost is that I may have more units conversions happening behind
the scenes. But they only occur when dealing with the numeric values
themselves - i.e., input/output. All my internal computations should
be occurring with my types length, time, speed, etc. - which would be
defined using a common set of units. For many users a little
conversion cost in I/O is of no consequence, if most of the time is
spent doing calculations on values in length, speed, etc. (Other
users can use the existing types that are tied to units.)

One benefit is that I could write all my code to be independent of
which units I choose, except where I need to specify a quantity
numerically (in which case I must specify units, of course). If I
later decide, say, the scale of my problem is more suited to eV than
kJ (or if some of my code is reused in a differently-scaled
application), I simply change the definitions for my "energy" class,
etc., and recompile! As Beth Jacobson suggested, perhaps there could
be an easy way for the user to select these "base units" for the
entire application.

To me, having types like "length," "speed," etc. is also easier to
understand. It might be a better starting place for illustrating the
library to new users. Here's an example of how I think about physical
quantities: My desk has a length. "Length in meters" or "length in
inches" are not properties of the desk - only length. That length can
then be expressed numerically in different units. A "length" object
would represent the desk's length in a similarly abstract way, which
could then be expressed in whatever units are desired for I/O. Of
course, internally the computer has to represent the length as a value
in some unit, but that would be encapsulated in the type and thus
transparent to the user. The same internal units would be used for
all quantities, thus avoidinng the overhead of type conversions
(except on I/O).

> > If my assumption that unit conversions are only needed when
> > numeric values are assigned to or extracted from dimensions is
> > correct, then dimensions don't really need to know about units.
> > The units functions would need to have a concept of default
> > dimension units so they'd know what they were converting from or
> > to, but the dimensions themselves wouldn't know or care.

Well said. I think this is the same as what I'm suggesting.

> > That would be the real benefit of this system. Reducing the number
> > of conversions and making units explicit at the point of
> > conversion may have some small benefit, but making the dimensions
> > library essentially unitless seems like a major advantage.
> >
> > Of course it's your library, and I'm not trying to dictate design.
> > But if you're looking for a way to make the dimensions library
> > essentially independent of units while retaining the unit safety
> > of the current system, this might be a direction to consider.

I agree.

-- Leland


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