Have you spent many hours debugging a program before you discovered the angular argument to a trig function was expressed in degrees instead of radians? Has a misplaced parenthesis ever caused one of your equations to produce strange results? Most of these kinds of errors can be detected at compile time if dimensional data types are used.
For example, consider the equation DISTANCE := (INDICATED_AIR_SPEED + WIND_SPEED) * TIME;. This equation will be correct only if the variables use consistent units (i.e. DISTANCE in feet, the two speeds in feet/second, and TIME in seconds). If TIME is in milliseconds, INDICATED_AIR_SPEED is in knots, and WIND_SPEED is in miles per hour, then DISTANCE can't possibly be correct. Even if consistent units are used, you won't get the correct answer if the parentheses are missing because the multiplication operation has higher precedence than addition.
If the compiler knows that two variables of type feet per second added together produce a result of type feet per second, and if it also knows that a variable of type feet per second multiplied by a variable of type seconds produces a result in feet, then the compiler can check the dimensional consistency of an equation for you. If you leave out the parentheses in the example above, the compiler will know that WIND_SPEED multiplied by TIME gives an answer in feet, and feet added to INDICATED_AIR_SPEED in feet per second won't give a correct answer in feet.
Ada's built-in type checking enables her to automatically check the dimensional consistency of all your equations at compile time, if you simply declare the variables to be dimensional units.
Let's look at Figure 5 closely to see how this is done. It uses a package called DIM_INT_32, which contains a dimensioned 32 bit data type Units. Feet and Meters are both new types derived from Units. The variables A, B, and C express distances in feet, but X, Y, and Z express distances in meters. Lines 13 and 14 of show that Ada's type checking will allow addition of distances in the same kind of units, but will prohibit you from accidentally adding distances in mixed units. If you really want to add a distance measured in feet to a distance in measured in meters, you can use Units_Convert to tell Ada you really want to do that, and she will automatically multiply by the proper scale factor.
A derived type has all the allowable values and operations of its parent type, but is an entirely different type. You can derive a type from any other type. You may wonder why I derived the type Feet from the type Units. Why not just derive it from integer?
Suppose I wrote type Kilograms is new integer;. This would create a new data type which could have any value from integer'FIRST to integer'LAST. It would also have all the integer operations defined for it. You could add two objects of type Kilograms and get a result of type Kilograms. You could not, however, add an object of type Kilograms to any other type object, integer or otherwise. This gives us some of the protection we desire.
Deriving Kilograms from integer does not give us a complete solution. Kilograms could be multiplied by Kilograms to get an incorrect answer in Kilograms because integers can be multiplied together, and so that property is automatically derived from the parent. Although Ada always allows you to add new operations to a data type, she never lets you take away operations derived from a parent. We can't derive dimensional units from the predefined integer data type and then remove unwanted operations. We have to start with a data type with fewer operations than we need, and add more operations to it.
Private types have no predefined operations except assignment, equality, and inequality. Those are useful operations for dimensional data types, so we are glad to inherit them. But private types don't have an addition operation defined for them. Therefore we have to specially define addition.
I published package called DIMENSIONAL_UNITS in the spring of 1987 [1] and put it in the public domain Ada Software Repository [2]. This package used private types as the parent types for integer and floating point dimensional units. It bothered me, however, that I lost automatic range checking for dimensional data types. That is, I couldn't define a data type Kelvin that automatically detected impossible (negative) temperatures.
I also didn't like the excessive size of the DIMENSIONAL_UNITS package. I put both integer and floating point data types in the package, so programs that needed only integer types also picked up some dead code associated with floating point types.
The DIMENSIONAL_UNITS package works fine, but there was room for improvement. The two generic packages (and their instantiations) that you are about to see include those improvements. They allow you to add range constraints, and separate the integer data types from the floating point data types, so you can selectively obtain the data types you need.
The Range_Checking_Example in Figure 6 shows how Ada can detect impossible values. In the declarative region I instantiated the generic FLOAT_UNITS package to get a new package called TEMPERATURE. I put range constraints on it by specifying MIN and MAX values. The MIN value is absolute zero on the Celsius scale. The MAX value is arbitrary. I could have used the default value, but you wouldn't have known what that value that was. I picked 32_000.0 for no particular reason.
In the body of the code I have three assignment statements, each enclosed in a block structure with an exception handler. You can consider them to be if-then-else structures. If the assignment statement succeeds, then the following line is printed. If the attempted assignment raises CONSTRAINT_ERROR, then the program jumps to the exception handler and prints the line found there.
The lines of output appended to the end of Figure 6 shows Ada found the errors when I ran the program.
[1] Do-While Jones, "Dimensional Data Types," Dr. Dobb's Journal of Software Tools, #127 May 1987, pp.50-62
[2] The Ada Software Repository is a collection of files containing reusable Ada components. These files are maintained by Richard Conn on a computer named SIMTEL20. SIMTEL20 can be reached by anyone who has a computer on the ARPA/MILNET network and File Transfer Protocol (FTP). See Richard Conn's The Ada Software Repository and the Defense Data Network, published by New York Zoetrope, 838 Broadway, New York, NY 10002.