[comp.lang.misc] Typing on units

sommar@enea.se (Erland Sommarskog) (03/15/90)

Marvin Rubenstein (marv@ism780.UUCP) writes:
>I am unaware of any commonly available language that prevents this form of
>mistake.  Look at the following:
>
>  double distance;
>  double time;
>  double velocity;
>
>  velocity = distance/time;  /* this makes sense */
>  velocity = distance+time;  /*  I mixed 'apples' and 'oranges' and produced
>	        		 a lemon :-) */

The program below contains the same error and does not compile.
I have edited the error messages to stay below 80 columns.

   PROCEDURE Type_test IS
   
       TYPE Meter             IS NEW Float;
       TYPE Seconds           IS NEW Float;
       TYPE Meter_per_seconds IS NEW Float;

       x : Meter   := 2.2;
       s : Seconds := 3.3;
       v : Meter_per_seconds;

       FUNCTION "/"(x : Meter; s : Seconds) RETURN Meter_per_seconds IS
       BEGIN
          RETURN Meter_per_seconds(x) / Meter_per_seconds(s);
       END "/";

   BEGIN
      v := x / s;
      v := x + s;
   --------^A
   ------------^B
   --A:error: RM 3.3: base type of expression must be meter_per_seconds, line 5
   --B:error: RM 3.3: base type of expression must be meter_per_seconds, line 5
   END Type_test;

In order to get division to work we had to define a function for it. 
In fact we have to define a function of a similar kind for every operation
we want to make. This is a lot of typing, on the other hand: it does
well document the rules at hand. Performance won't be an issue. In 
the sample above, the subprogram would disappear rapidly in the hands
of the optimizer. Normally it would be part of a package, but you
would mention in it in the INLINE pragma.
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se

news@ism780c.isc.com (News system) (03/16/90)

In article <883@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>Marvin Rubenstein (marv@ism780.UUCP) writes:
  I (Marv Rubinstein) talked about using units for an aid in error
   detection.

[Erland Sommarskog responded]
:The program below contains the same error and does not compile.
:I have edited the error messages to stay below 80 columns.
:
:   PROCEDURE Type_test IS
:
:       TYPE Meter             IS NEW Float;
:       TYPE Seconds           IS NEW Float;
:       TYPE Meter_per_seconds IS NEW Float;
:
:       x : Meter   := 2.2;
:       s : Seconds := 3.3;
:       v : Meter_per_seconds;
:
:       FUNCTION "/"(x : Meter; s : Seconds) RETURN Meter_per_seconds IS
:       BEGIN
:          RETURN Meter_per_seconds(x) / Meter_per_seconds(s);
:       END "/";
:
:   BEGIN
:      v := x / s;
:      v := x + s;
:   --------^A
:   ------------^B
:   --A:error: RM 3.3: base type of expression must be meter_per_seconds, line 5
:   --B:error: RM 3.3: base type of expression must be meter_per_seconds, line 5
:   END Type_test;
:
:In order to get division to work we had to define a function for it.
:In fact we have to define a function of a similar kind for every operation
:we want to make.


The language I had in mind was more like this.

     units
       m              -- mass
       l              -- length
       t              -- time
       f = m*l/(t*t)  -- force
     end units
     data
       velocity :real, unit l/t;
       distance :real, unit l;
       time     :real, unit t;
       area     :real, unit l*l;
     end data
     velocity = area/(time*distance); -- this is ok
     area     = distance*distance;    -- so is this
     time     =velocity/distance;     -- not good
     area     =distance+distance;     -- bad

The actual language that I was refering to also allowed conversion
constants (e.g. for feet to meters) to appear in the units declarations.
Thus, conversions were inserted automatically by the compiler.  What you are
suggesting would, in my opinion, make the programming of a large scientific
computation almost impossible.

     Marv Rubinstein

djones@megatest.UUCP (Dave Jones) (03/17/90)

From article <40346@ism780c.isc.com), by news@ism780c.isc.com (News system):
) In article <883@enea.se) sommar@enea.se (Erland Sommarskog) writes:
))Marvin Rubenstein (marv@ism780.UUCP) writes:
)   I (Marv Rubinstein) talked about using units for an aid in error
)    detection.
...
) The language I had in mind was more like this.
) 
)      units
)        m              -- mass
)        l              -- length
)        t              -- time
)        f = m*l/(t*t)  -- force
)      end units


I think the catch-phrase here is 'dimensional analysis'. It's not
hard to do. I've implemented it in a Pascal superset. It can be
done by the compiler if things are simple enough, or at runtime
otherwise. You could do a pretty good job of it in C++ without touching
the compiler, relying on runtime checks, of course.

The trick is to keep, along with each value, an array of integers, one
for each dimension, e.g. mass, length, time, force. When values are
multiplied, their dimensions are added. Get it?

For example, pure 'length' would have a dimension of (0,1,0,0) -- a one
in the length-dimension. 'time' would have a dimension of (0,0,1,0) -- a
one in the time dimension. 'length/time' would have the dimension
(0,1,-1,0) -- the dimension of length _minus_ the dimension of time.
Because division is the inverse of multiplication, the time dimension
is _subtracted_.

I think you can work out the rest.

sommar@enea.se (Erland Sommarskog) (03/20/90)

Marvin Rubenstein (marv@ism780.UUCP) writes:
>  I (Marv Rubinstein) talked about using units for an aid in error
>   detection.

Where upon I suggested a method of implementing this in Ada.

Marvin responds:
>The language I had in mind was more like this.
>
>     units
>       m              -- mass
>       l              -- length
>       t              -- time
>       f = m*l/(t*t)  -- force
>     end units
>     data
>       velocity :real, unit l/t;
>       distance :real, unit l;
>       time     :real, unit t;
>       area     :real, unit l*l;
>     end data
>
>The actual language that I was refering to also allowed conversion
>constants (e.g. for feet to meters) to appear in the units declarations.
>Thus, conversions were inserted automatically by the compiler.  What you are
>suggesting would, in my opinion, make the programming of a large scientific
>computation almost impossible.

I was fully aware of what I proposed was not really what you wanted,
on the other hand, I don't see any important conceptual difference
in your out-line. Your notation is far more compact that the Ada
package you would have to write, but once you would had it done,
you could go ahead and program your computation. And the package
would still be there the next time. Or did I miss something? What 
in my proposal would make your program impossible to write?
  The gain, as I see it, with the Ada solution is that we are saved
another language with some quite special features that are not of
general interest, but instead we implement those features with
general mechanisms. After all, there are plenty of applications
where units plays about no role at all.

There is one point where Ada fails, though. If you declare:
    US_distance         : Feet;
    Real_world_distance : Meter;
you cannot simply write:
   Real_world_distance := US_distance;
but have to rely on a conversion routine:
   Real_world_distance := Feet_to_meter(US_distance);
since Ada doesn't provide overloadable assignment. What's
worse is that:
   Real_world_distance := Meter(US_distance);
is a legal, but does only move the bits from the right-hand
side to the other, and thus constitute a trap you may fall in.
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se

karl@haddock.ima.isc.com (Karl Heuer) (03/22/90)

In article <907@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>Marvin Rubenstein (marv@ism780.UUCP) writes:
>>[about having dimensional analysis built into a language]
>
>I was fully aware of what I proposed was not really what you wanted,
>on the other hand, I don't see any important conceptual difference
>in your out-line. Your notation is far more compact that the Ada
>package you would have to write, but once you would had it done,
>you could go ahead and program your computation. And the package
>would still be there the next time.

The problem is that there are a *lot* of distinct types: a true dimensional
analysis language would accept "meter^3/(kilogram*second^2)" automatically; in
Ada it works only if the package author had the foresight to include it.

>[One pitfall in Ada is that you] have to rely on a conversion routine:
>   Real_world_distance := Feet_to_meter(US_distance);

Or just use a predefined constant of the appropriate type:
    Real_world_distance := METERS_PER_FOOT * US_distance;
since the dimensional analysis will keep you from doing it backwards.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint