From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,66bb9de12d0a33f9,start X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-12-02 17:38:39 PST Newsgroups: comp.lang.ada Path: bga.com!news.sprintlink.net!hookup!news.mathworks.com!zombie.ncsc.mil!news.duke.edu!godot.cc.duq.edu!hudson.lm.com!netline-fddi.jpl.nasa.gov!nntp-server.caltech.edu!news.ridgecrest.ca.us!owens!do_while From: do_while@owens.ridgecrest.ca.us (Do-While Jones) Subject: Dimensional Data Types Message-ID: Sender: usenet@ridgecrest.ca.us (Ridgenet Usenet admin) Organization: RidgeNet - SLIP/PPP Internet, Ridgecrest, CA. (619) 371-3501 Date: Sat, 3 Dec 1994 00:06:26 GMT Date: 1994-12-03T00:06:26+00:00 List-Id: The dimensional data type issue keeps coming up. The latest exchange was in CLA article 2709. > ron house wrote: > How about "Ada - use it when you want to multiply a length by a length > and get a length, or when you want to be prevented from dividing an area > by a length because they have different types." > (PS: yes, you can fix that by defining zillions of additional *,/,- and + > functions, but good grief...) He got a response FROM: "Bennett, Chip (KTR) ~U" > It seems to me that how many functions you have to define depends on how > you approach the problem. Let's start with the premise that there are > many triples of numbers that exhibit similar relationships. For example: > > 1) length, 2 (squared), area > 2) length, 3 (cubed), volume > 3) length, N, hyperspace :-) > > Or perhaps a different relationship: > > 1) speed, time, distance > 2) principle, rate, interest > 3) mass, acceleration, force > 4) current, resistance, voltage > 5) mass, (light speed) squared, energy > 6) large unit of measure, constant, small unit of measure > > Now, we ought to be able to create a generic package that declares a set > of allowable functions for a particular relationship > (A := B * C, C := A / B, etc.). > Then we could create a package that declares a set of private types > (i.e. speed, time, and distance) and instantiates the generic package of > math functions using the private types. Since the types are private they > are limited to the functions in the instantiated generic. > Area := Length ** 2 is allowed, but Length := Length ** 2 is not > allowed. > > In Ada 83 there is a limitation in that we can't extend the set of > allowable functions for some triple that has some _extra_ relationship > that the others don't have, but child packages in Ada 9X would allow for > adding new functions to the private type. > > Given that there is a fairly limited set of relationship groups for > triples that make sense in the real world, I doubt you would have to > write very many additional math functions. > > All that said, I've never actually tried this, but it seems plausible. > Any thoughts? I have tried it, and it works very well, but I'm getting ahead of myself. Dimensional data types were proposed for Ada 9X, but they were rejected. They weren't rejected because they aren't useful. They were rejected because it was possible to build them perfectly well in Ada 83, so there was no need to add special language features to support them. (That's the beauty of Ada. You don't have to make special features part of the language. The language is powerful enough that you can build special features exactly the way you like them.) Ada 9X has even more power, so it might be possible to come up with even better dimensional data types in Ada 9X. Some Ada programmers apparently do something like this: AREA := Area_type(LENGTH) * Area_type(LENGTH); This appears to be a knee-jerk reaction to a compiler type-mismatch error message. I think that is a really bad response because one could just as easily write AREA := Area_type(SPEED) * Area_type(LENGTH); which is certainly wrong. That is no more safe than declaring all the variables to be type FLOAT (which is another common "solution" to the "problem" of Ada's strong typing.) Most of the work I do involves scientific calculations. I use dimensional data types ALL the time. They have saved my bacon more times than I care to remember. Not only that, they make it much easier for me to reuse my software components because all my components are based on a common set of basic data types. I spent a little bit of effort years ago creating the abstraction, and now I can use the abstraction as easily as I can write, "with TIME_UNITS;" or "with ELECTRICAL_UNITS;". First, I created two generic packages, INTEGER_UNITS and FLOAT_UNITS, which define private data types with the operators that make sense for dimensioned data types. The only difference in these packages is that one can be instantiated for integer data types, and the other can be instantiated for real data types. Second, I instantiated them for INTEGER, INTEGER_32, FLOAT, LONG_FLOAT, etc. Usually I instantiate them without range constraints, but in the case of temperature data types I use absolute zero as the lower limit. Third, I created several non-generic packages that DERIVE particular kinds of dimensional units from the Units type in the instantiation of the appropriate generic package. For example, DIM_FLOAT is the instantiation of FLOAT_UNITS for type FLOAT. So, I simply write, "type Feet is new DIM_FLOAT.Units;". This creates a type Feet which has all the desired properties. I divided the dimensional units into consistent sets. This makes it possible for me to add packages with new types for a new problem domain without making all my previous work obsolete. (I don't do any nuclear physics work, so I don't have any data types that supports that problem domain. But I could add a package with those data types without affecting anything I have already done.) The packages I use all the time are: ANGULAR_UNITS: This packages defines the types Degrees and Radians, conversions between them, and the constant PI. TIME_UNITS: This package defines the type Milliseconds, Seconds, and Hertz. The Seconds data type is a floating point type that I use for time calculations. Hertz is a floating-point type that can be multiplied by Seconds with a dimensionless result. Milliseconds is an integer type used to represent the time of day to 1 millisecond accuracy. (Most of the data I work with is tagged with IRIG-B time tags, to 1 millisecond resolution.) I overloaded the Milliseconds relational operators (">", ">=", etc.) to take into account midnight, so 1 AM is later than 11 PM. This was easily done in Ada 83, even without tagged types or modular types. I also gave the Milliseconds type functions called Image and Value that convert to and from 12 character strings of the form "HH:MM:SS.XXX". ELECTRICAL_UNITS: This package defines types needed for electrical engineering problems. It's specification is: with DIM_FLOAT; package ELECTRICAL_UNITS is type Volts is new DIM_FLOAT.Units; type Amps is new DIM_FLOAT.Units; type Ohms is new DIM_FLOAT.Units; type Watts is new DIM_FLOAT.Units; type dBs is new DIM_FLOAT.Units; -- Ohm's Law (E = IR) function "*"(I : Amps; R : Ohms) return Volts; function "*"(R : Ohms; I : Amps) return Volts; function "/"(E : Volts; R : Ohms) return Amps; function "/"(E : Volts; I : Amps) return Ohms; -- Watt's Law (P = IE) function "*"(I : Amps; E : Volts) return Watts; function "*"(E : Volts; I : Amps) return Watts; function "/"(P : Watts; E : Volts) return Amps; function "/"(P : Watts; I : Amps) return Volts; -- Decibels are defined to be: -- 10 Log10(Measured Power / Reference Power) -- Assuming a constant resistance, the definition is -- equivalent to: -- 20 Log10(Measured Voltage / Reference Voltage) -- The following operators include the Log (or antilog) operation -- as part of the division (or multiplication). function "/"(MEASURED, REFERENCE : Watts) return dBs; function "*"(DB : dBs; REFERENCE : Watts) return Watts; function "/"(MEASURED, REFERENCE : Volts) return dBs; function "*"(DB : dBs; REFERENCE : Volts) return Volts; end ELECTRICAL_UNITS; BRITISH_UNITS: This package defines types needed for mechanical engineering (or classical physics) problems. It starts out like this: with DIM_FLOAT, TIME_UNITS; package BRITISH_UNITS is type Feet is new DIM_FLOAT.Units; type Sq_feet is new DIM_FLOAT.Units; type Cu_feet is new DIM_FLOAT.Units; type Feet_per_sec is new DIM_FLOAT.Units; type Feet_per_sec_sq is new DIM_FLOAT.Units; type Pounds is new DIM_FLOAT.Units; type Slugs is new DIM_FLOAT.Units; type Pounds_per_sq_inch is new DIM_FLOAT.Units; type Slugs_per_cu_foot is new DIM_FLOAT.Units; type Foot_pounds is new DIM_FLOAT.Units; type Horsepower is new DIM_FLOAT.Units; type Slug_foot_per_sec is new DIM_FLOAT.Units; G : constant Feet_per_sec_sq := +32.1740; -- and "*" and "/" operators for mixed types, including Seconds -- from the TIME_UNITS package. ENVIRONMENTAL_UNITS: This package defines pressure, relative humidity and temperature data types. Since I use it for problems that involve atmospheric pressure, it defines a pressure type "mm_Hg" and functions that convert millimeters of mercury to PSI, and vice versa. I find these packages to be very useful. They make my code easy to read (because declarations like "DISTANCE : Feet;" are less ambiguous than "DISTANCE : Length_type;"). As a general rule, I don't use USE clauses, but I do USE the dimensional packages so the dimensional types, constants, and operators are visible. (Ada 9X has a limited USE clause for people who are not permitted to use USE clauses which could be used instead.) [If you have written a natural language parser, test it on the previous sentence. If it can parse that sentence, it can parse anything! :-) ] Since the USE clause makes the operators visible, I just write things like "VELOCITY := DISTANCE / TIME;" and Ada does all the dimensional checking for me. If I write "VELOCITY := DISTANCE / VOLTS;", I naturally get an error message. Of course I can respond to the error message by doing something really stupid, like "VELOCITY := DISTANCE / Seconds(VOLTS);", but I am not that dumb yet. So, Ada 83 has a perfectly good way to represent dimensional data types. You have to define the operators, but there aren't "zillions" that need to be defined. Ada 9X gives you even more ways to create dimensional data types, so there is possibly an even better solution in Ada 9X. If you don't want the safety and clarity that dimensional data types give you, you can just declare everything to be FLOAT, like you would in C. You don't have to use dimensional types if you don't want to. Do-While Jones -- +--------------------------------+ | Know Ada | | [Ada's Portrait] | | Will Travel | | wire do_while@ridgecrest.ca.us | +--------------------------------+