[GSoC Proposal] Statically Checked Measurement Units

spir denis.spir at gmail.com
Mon Mar 28 10:15:18 PDT 2011


On 03/28/2011 05:43 PM, Cristi Cobzarenco wrote:
> Thus, the requirements for the unit system would be:
> 1. One line definition of new units.
> 2. Simple, yet safe and explicit conversion between units.
> 3. Zero runtime overhead.
> 4. Minimal extra coding effort to use units.

I like your study very much. Measurement units are, for me, kinds of conceptual 
types --as opposed to primitive types. I think they would be welcome, possibly 
for Phobos.

> [...]
> I propose using types for base units and mixins to define derived units.
>  One can use the typenames of the units in arithmetic operations this way:
>
> struct metre  {}
> struct second {}
>
> void f() {
> Quantity!("metre")        dist1 = quantity!(3.0, "metre");
> Quantity!("metre^2")      area  = dist1 * dist1;
> Quantity!("metre/second") speed = dist1 / quantity!(2.0, "second");
> }

I think (not sure) this could be even simpler:
   1. Thank to D's very used auto feature, avoiding double specification of the 
type; you could get rif of quantity, if it's only a convenience factory func.
   2. I guess it's not needed for the user to give a quantity type to 
/constants/ (here 2.0). It is /meant/ to be a a number of seconds. This, as 
opposed to measure /variables/.
Thus, we possibly could have:

     auto dist1 = Quantity!("meter")(3.0);
     auto area  = Quantity!("metre^2")(dist1 * dist1);
     auto speed = Quantity!("metre/second")(dist1 / 2.0);

(Unsure whether your system could automagically infer the unit of area. ?)

I'm not fan of using strings as unit identifiers. Why don't you want to use use 
the corresponding types (structs or classes) themselves?

      auto dist1 = Quantity!Meter(3.0);

Thus requiring each unit to be identified by a (possibly empty) struct or 
class. This also gives the opportunity for the user to actually implement some 
useful stuff in there; or to *reuse* existing types for things-to-be-counted 
(in the latter case, measures would actually be integer /counts/); see your 
Widget vs Gadget example below).

> Conversion between units can be done specifying a single factor with a
> proper unit:
>
> template conversion( alias unit : "kilometer/meter" ) {
> immutable Quantity!(unit) conversion = quantity!(123.0,unit);
> }

Unsure of the right approch here. All we need is a registered conversion factor 
for every needed (U1,U2) pair. It could be a kind of 2D associative array with 
unit keys and float values. Then, would it be possible to have a single convert 
template, like:

     Quantity!U2 convert (string U1, string U2) (Quantity!U1 measure) {
         auto factor = conversionFactors[U1][U2];   // throws if undefined
         return Quantity!U2(measure * factor);
     }

?

> void f() {
> Quantity!("metre")     d1 = quantity!(123.0,"metre");
> // convert calls conversion! with the right argument
> Quantity!("kilometre") d2 = convert!(d1,"kilometre");
> }

    auto d1 = Quantity!("metre")(123.0);
    auto d2 = convert!(d1,"kilometre");
or using my approach:
    auto d2 = convert!("metre","kilometre")(d1);

Here the type for d2 is really unnecessary.

> Also, notice this approach imposes no restriction to the types that define
> units, therefore our Widget/Gadget counters could be defined without any
> extra work:
>
> class Widget { /* complicated class definition */ }
> class Gadget { /* complicated class definition */ }
>
> Quantity!("Widget",int) nWidgets;
> Quantity!("Gadget",int) nGadgets;

See note about identifying units above.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com



More information about the Digitalmars-d mailing list