physical units checked at compile time (yet lacking IFTI capabilities)
BCS
BCS_member at pathlink.com
Sun Apr 23 13:10:10 PDT 2006
I feel your pain. A few post back I include a link to a unit.d program that does
just what you are trying to do, but a run time (with all of the costs :-p that
entails, OTOH it lets you do units dynamically) I have bean waiting for better
template support to do exactly the same project you are looking at. Until that
happens I think we're sunk.
I was looking at something like this:
struct Unit(T, int L, int M, int T)
{
T val;
Unit(T, L, M, T) opAdd(Unit(T, L, M, T) op)
{
Unit(T, L, M, T) ret = { val : val+op.val };
return ret;
}
// this will need some improvements to templates
Unit(T, L+opL, M+opM, T+opT) opMul(Unit(T,opL, opM, opT) op)
{
Unit(T, L+opL, M+opM, T+opT) ret = { val : val*op.val };
return ret;
}
..
}
Lets hope walter makes some of these possible in the near future.
In article <e2gc64$bqv$1 at digitaldaemon.com>, Norbert Nemec says...
>
>I just wanted to try some ideas based on templates. After a long odyssee
>through the details of D template programming, I finally succeeded to
>arrive at a working piece of code, even though it is still a long way
>from where I hoped to arrive.
>
>I think it is interesting to share this experience for several reasons:
>
>* It shows a promising idea how to handle and check physical dimensions
>along with unit conversions at compile time.
>* It gives a good example where IFTI would be crucial.
>* It illustrates a point where IFTI does not work yet.
>* Somebody may be able to give me further ideas about how to go on.
>
>***********************************************
>
>Let me explain:
>
>The ultimate goal was to handle physical dimensions as compile time.
>Basically, I would then be able to write code like:
>
>-----
>| mass m = 0.5 * ounce;
>| velocity v = 1.0 * km / hour;
>| energy E_kin = 0.5 * m * v*v;
>| printf("E_kin = %g kcal\n",E_kin/kcal);
>-----
>
>and so on, where all the dimensions are checked at compile time and all
>necessary conversions are done automatically.
>
>I started out with the basic idea:
>
>-------------------
>| struct physical_quantity(
>| int m, // length
>| int s, // time
>| int kg // mass
>| // ignore A, K, mol and cd for the moment
>| ) {
>| double value;
>| }
>|
>| alias physical_quantity!(1,0,0) length;
>| alias physical_quantity!(0,1,0) time;
>| alias physical_quantity!(0,0,1) mass;
>|
>| const length meter = { value: 1.0 };
>| const time second = { value: 1.0 };
>| const mass kilogram = { value: 1.0 };
>-------------------
>
>which could be continued like:
>
>-------------------
>| alias physical_quantity!(1,-1,0) velocity;
>| alias physical_quantity!(2,-2,1) energy;
>|
>| const time minute = { value: 60.0 };
>| const time hour = { value: 3600.0 };
>| const velocity speedoflight = { value: 299792458 };
>| const energy Joule = { value: 1.0 };
>| const energy kcal = { value: 4185.0 };
>-------------------
>
>So far, everything worked fine. Now, I wanted to continue defining the
>multiplication such that I could do, for example:
>
>-------------------
>| physical_quantity!(1,4,-2) v1 = { value: 1.0 };
>| physical_quantity!(2,-4,1) v2 = { value: 1.0 };
>| physical_quantity!(3,0,-1) prod = v1 * v2;
>| // internally, equivalent to: prod.value = v1.value * v2.value;
>-------------------
>
>but I failed horribly trying to define this multiplication.
>
>The most promising try so far was:
>
>-------------------------------
>| struct physical_quantity(
>| int m,
>| int s,
>| int kg
>| ) {
>| double value;
>|
>| const int _m = m;
>| const int _s = s;
>| const int _kg = kg;
>|
>| template opMul(T) { // line 12
>| physical_quantity!(m+T._m,s+T._s,kg+T._kg) opMul(T other) {
>| physical_quantity!(m+T._m,s+T._s,kg+T._kg) res;
>| res.value = value*other.value;
>| return res;
>| }
>| }
>| };
>|
>| int main(char[][] args)
>| {
>| physical_quantity!(1,0,0) v1; v1.value = 1.0;
>| physical_quantity!(0,1,0) v2; v2.value = 1.0;
>| physical_quantity!(1,1,0) prod = v1*v2; // line 25
>| printf("%f\n",prod.value);
>| return 0;
>| }
>--------------------------------
>
>which fails with the compiler error:
>
>------------
>| units_minimal.d(25): incompatible types for ((v1) * (v2)):
>'physical_quantity' and 'physical_quantity'
>| units_minimal.d(25): 'v1' is not an arithmetic type
>| units_minimal.d(25): 'v2' is not an arithmetic type
>| units_minimal.d(25): cannot implicitly convert expression ((v1) *
>(v2)) of type physical_quantity to physical_quantity
>------------
>
>My guess was that the problem is with the operator overloading, and
>indeed, replacing line 25 by
>-------------
>| physical_quantity!(1,1,0) prod = v1.opMul(v2); // line 25
>-------------
>
>changes the compiler error to:
>
>------------
>| units_minimal.d(12): template
>units_minimal.physical_quantity!(1,0,0).physical_quantity.opMul(T)
>templates don't have properties
>| units_minimal.d(25): function expected before (), not v1 of type
>physical_quantity
>| units_minimal.d(25): cannot implicitly convert expression ((v1)((v2)))
>of type int to physical_quantity
>------------
>
>My next guess was, that the IFTI causes the problem, so I changed lines
>12 and 25 to
>
>------------
>| template T_opMul(T) { // line 12
>------------
>| physical_quantity!(1,1,0) prod =
>v1.T_opMul!(typeof(v2)).opMul(v2); // line 25
>------------
>
>and now the program worked correctly.
>
>Of course, in this state, the whole code is far from useful. Without
>IFTM and operator overloading, the whole point of the library is moot:
>allowing readable code with compile-time error checking.
>
>Even if IFTI and operators would work, there is, of course, some way to
>go for a working library, but I am confident, that this it will be
>possible to go that way.
>
>Greetings,
>Norbert
More information about the Digitalmars-d
mailing list