Monday 16 January 2006

The Inner Drive Extensible Architecture™ contains a very useful namespace called Quantitative that contains classes and interfaces to use in measuring things. Essentially, there is a trio of interfaces, IQuantity, IUnit, and IPhenomenon, that allow you to create and convert any kind of measurements. The principal implementation of IQuantity is the Numeric structure.

To convert feet to meters, you do this:

IQuantity feet = new Numeric(100, new Foot());
IQuantity meters = quantity.ConvertTo(new Meter());

Even though that looks simple, it has always troubled me. I've realized in the last couple of days that I got the abstractions wrong.

In any object model, you want to work with the most convenient abstractions. It helps if the resulting code looks like English (or whatever your native language is). Quantity, Unit, and Phenomenon are, indeed, abstractions, but they're not the right ones. Here's how I know.

First, the following compiles fine, but throws an InvalidOperationException when executed:

Numeric feet = new Numeric(100, new Foot());
Numeric fahrenheit = new Numeric(100, new Fahrenheit());
Numeric hotFeet = feet + fahrenheit;

Numeric is too abstract, you see.

Also, getting feet to display as, say, kilometers becomes very annoying:

Numeric feet = new Numeric(10000, new Foot());
Numeric meters = (Numeric)feet.ConvertTo(new Meter());
Console.WriteLine(meters.ToString());
// "3048 m" displayed

// Numeric.Unit exposes a Unit which may or may not be metric
IExponential exponent = (IExponential)meters.Unit;
exponent.Exponent = MetricExponent.Kilo;

Console.WriteLine(meters.ToString());
// "3.048 km" displayed

The Numeric structure doesn't care about the metric exponent of its Unit member. Why should it? It contains a value and a unit, and if you add two Numeric objects that use the same Unit, you get exactly what you'd expect.

But why should the Unit care what its exponent is? Now, when converting to or from other Units, it has to take that extra piece of information into account, or the conversions will be off by orders of magnitude.

There are many other problems and annoyances with the Quantitative namespace, which took me months to tease out. But this morning, on the El, I cracked the code (as my dad would say).

Tell me, doesn't this make a lot more sense?

Length meters = new Length(3000, new Meter());
// Alternate syntax using the implicit operator:
// Length meters = 30;
Console.WriteLine(feet.ToString());
// "3000 m" displayed

Length feet = meters.ConvertTo(new Foot());
Console.WriteLine(feet.ToString());
// "9842.52 ft." displayed

Console.WriteLine(feet.ToString(MetricExponent.Kilo));
// "9842.52 ft." displayed; no exception; simply ignored the exponent
Console.WriteLine(meters.ToString(MetricExponent.Kilo));
// "3 km" displayed

And, of course, our earlier example wouldn't even compile:

Length meters = 30;
Temperature fahrenheit = meters.ConvertTo(new Fahrenheit());
// Won't compile

I'll be refactoring this soon. Everything else I'm building depends on it. Watch this blog for a link to the new demo.

Tuesday 17 January 2006 04:29:22 UTC
So when are you going to start teaching people how to write code? Your documentation is so elegant and readable, and your comments so informative, I honestly don't understand why you haven't yet been tapped to teach these profound subtleties to other programmers.

And man, do you ever sound like your father when you write. That apple sure didn't fall far from the tree.
Comments are closed.
Search
Navigation
Categories
On this page....
Archives
<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
Total Posts: 65
This Year: 1
This Month: 0
This Week: 0
Comments: 9
Blogroll
Contact me
Send mail to the author(s) E-mail RSS 2.0 Atom 1.0
Administration