Preliminary submission - std.rational and std.typelist

David Nadlinger see at klickverbot.at
Sat Oct 6 14:18:23 PDT 2012


On Saturday, 6 October 2012 at 19:40:10 UTC, Arlen wrote:
> Besides, the math behind it is sound and and many years of hard 
> work has gone into it.

Also, it is extremely complicated by the fact that it somehow has 
to work withing the boundaries of C++ and boost::mpl and friends.

> I do want to mention that the distinction between dimension and 
> unit is important.

Why? From a theorist standpoint, there of course is a distinction 
between the two, yes. In practice, however, a dimension is simply 
a connected component in the graph of (non-composite) units, 
where the edges represent known conversions, i.e. a dimension is 
just a name for a set of units which can converted into each 
other. The concept of dimensions arises naturally, and no rigor 
is lost by not explicitly having it; there is no need to force 
the redundancy on the programmer.

In fact, my library was also based on dimensions originally, but 
at some point, they became an annoyance in the code I wrote using 
it, and I discovered that I could do perfectly fine without them.

> I rather see this:
>
> Quantity!(length, float) a = 2 * metre;
>
> than this:
>
> Quantity!(metre, float) a = 2 * metre;

Really? The first has the problem that you have absolutely no 
idea what a is really represented like in memory – you need to 
have a canonical base unit all other units are automatically 
converted to. One consequence of that is that you are forced to 
do a lot of unneeded conversions if you can't completely work in 
that base unit, for example for interfacing with code that 
doesn't use your unit system. You also can't just transparently 
tack a unit on a quantity in places where the actual value is 
important, think serialization, ABI boundaries, etc. Not being 
able to chose your representation might also lead to precision 
issues if you are working with base types of limited width.

In contrast, the concept of dimensions is easy to implement in 
terms of units. For example, you could just define 'isLength' as 
'canConvert!meter' (it will accept any unit which can somehow, 
maybe not directly, converted into meters), and then implement a 
function like this:

---
auto squareArea(T)(T side) if (isQuantity!T && isLength!(T.unit)) 
{
   return side * side;
}
---

squareArea now works transparently and without overhead with all 
unit types. Of course, you could also define the parameter as 
just Quantity!(meter, T) or Quantity!(meter, float) if for some 
reason you want to, for example because you are only working in 
meters anyway and you don't want to have a template function to 
avoid the (compile-time) overhead.

I think the main reason why Boost.Units went with dimensions is 
that having a distinguished "canonical" unit for each dimension 
relieves the burden on the implementation in so far as you never 
have to synthesize code for arbitrary conversions, as your data 
is always stored in that canonical unit.

David


More information about the Digitalmars-d mailing list