TYPE DECLARATIONS AND SUBTYPES


1. TYPE DECLARATIONS

There are many situations where it is desirable for programmers to define their own types. For example:

  1. To enhance clarity and readability.
  2. To obtain a better representation of reality.
  3. To facilitate automatic checks on values.

i.e. to produce more reliable programs. Programmer-defined types are presented using a type declaration statement. This binds a "new" type definition to a type name (whereas a data declaration statement binds an existing type definition to a data item name). Type declaration statements have the general form:

type <TYPE_NAME> is <TYPE DEFINITION> ;

Some example type declarations incorporating specific ranges and/or precisions:

type SCORE is range 0 .. 100;

type TEMPERATURE is digits 3;

type PERCENTAGE is digits 4 range 0.0 .. 100.0;

Note that in each case the compiler will deduce that the types SCORE and TEMPERATURE are integer types. Similarly the compiler will deduce that the type PERCENTAGE is a floating point type, but only (in the case of the ICC compiler) if the number of digits is also specified. For example X: FLOAT is range 0.0 .. 100.0; will not compile. Once the above types have been declared they can be utilised in the usual manner:

A_VALUE: SCORE;

SUMMER: TEMPERATURE := 20;

X_VALU, Y_VALU: PERCENTAGE := 100.0;

A type declaration statement can also be used to rename an existing type, for example to use a more descriptive (application dependent) type name for a particular type. For example:

type REAL is float;

Here an alternative name for the pre-defined type FLOAT has been declared.


2. EXAMPLE PROBLEM CENTIGRADE TO FAHRENHEIT CONVERSION


2.1 Requirements Analysis

To produce a program that converts air temperature measured in whole numbers of degrees on the Centigrade scale to the equivalent on the Fahrenheit scale. Assume a minimum centigrade temperature of -50 and maximum of 100. Use the following conversion identity:

F = (9/5 x C) + 32

Output should be accurate to one decimal place.


2.2 Design

Commence with a top down analysis of the problem as illustrated by the hierarchy presented below:

TOP DOWN ANALYSIS

A single procedure will be sufficient to implement these operations:

  1. CENT_2_FAHR (top level procedure): Input Centigrade, convert to Fahrenheit, and output Fahrenheit.
    NAMEDESCRIPTIONTYPERANGE
    CENT_TEMPInput variableCENTIGRADE-50..100
    Where CENTIGRADE is a programmer defined type.
NASSI_SHNEIDERMAN CHART

A Nassi-Shneiderman design is presented to the right.


2.3. Implementation

-- CENTIGRADE TO FAHRENHEIT CONVERSION
-- 4 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure CENT_2_FAHR is
        type CENTIGRADE is range -50..100;
        package INTEGER_INOUT is new INTEGER_IO(CENTIGRADE);
        use INTEGER_INOUT;
        package FLOAT_INOUT is new FLOAT_IO(FLOAT);
        use FLOAT_INOUT;
        CENT_TEMP: CENTIGRADE;
begin
-- Input centigrade value
        PUT_LINE("Input temperature in degrees Centigrade: ");
        GET(CENT_TEMP);
-- Conversion and output
        PUT("The equivalent in degrees Fahrenheit is: ");
        PUT(FLOAT(CENT_TEMP) * (9.0/5.0) + 32.0, FORE=>3, AFT=>1, EXP=>0);
        NEW_LINE;
end CENT_2_FAHR;

Notes

  1. In the above code we have created a programmer defined type, CENTIGRADE, with an appropriately defined range.
  2. The output is in the form of a FLOAT.
  3. A type conversion is included, FLOAT(CENT_TEMP), so as to convert the CENTIGRADE data type value into a FLOAT data type value.
  4. We have used the INTEGER_IO template to create a new package to input/output data items of the type CENTIGRADE.
  5. Similarly we have used the FLOAT_IO template to create a package to input/output data items of the type FLOAT.

2.4. Testing

TEST CASEEXPECTED RESULT
CENT_TEMPFAHR_TEMP
-51DATA_ERROR
-50-58.0
-49-56.2
99210.2
100212.0
101DATA_ERROR

BVA and limit testing: Use Boundary Value Analysis testing to analyse limits of input variables. Suitable boundary values for CENT_TEMP are -51, -49, 99 and 101 (just above and below the range limits). We should also test the effect of inputs at the limits, e.g. -50 and 100. An appropriate set of test cases is given in the table (right).

Arithmetic testing: In addition we should also carry out some arithmetic testing to ensure the calculation part of the program operates appropriately. This normally involves tests using positive, zero and negative sample input values. Test cases involving positive and negative input values have already been designed with respect to BVA testing (see above) thus we only need to consider an input value of 0. An appropriate test case is defined in the table (right).

TEST CASEEXPECTED RESULT
CENT_TEMPFAHR_TEMP
032

Data validation testing: Finally the code should be tested using a number of spurious input values not previously incorporated into test cases.


Example Problem Centigrade to Fahrenheit Conversion Report.


3. SUBTYPES

Given a particular problem it is sometimes useful to introduce a type which can take values that are some subset of an existing type. Such types are referred to as subtypes. Subtypes are declared in a very similar manner to that in which programmer defined type declarations are made except that the keyword subtype is used. Examples of subtype declarations can be found in the package standard that is always automatically linked in to Ada programs and therefore does not require with and use statements). This package (amongst other things) contains two subtypes of the type INTEGER which are declared as follows:

subtype NATURAL is INTEGER range 0..INTEGER'LAST;

subtype POSITIVE is INTEGER range 1..INTEGER'LAST;

(note the use of the integer attribute last). Use of subtypes offers similar advantages to those associated with the use of programmer defined types:

  1. Readability.
  2. Good representation of reality.
  3. Error checking.

3.1. When to use Type and Subtype Declarations

Both offer similar advantages when closely related objects are in use and many computations are to be made using them. However, generally speaking, where a data item is required to display many of the features of the standard INTEGER or FLOAT types a subtype declaration should be used. Type declarations are usually used to describe what are termed compound types (e.g. arrays), but more on this later.


4. EXAMPLE PROBLEM VERTICAL MOTION


4.1 Requirements

Given the start velocity of a ball which is thrown vertically upwards from ground level, design and implement an Ada program that determines:

  1. The maximum height reached, and
  2. The time taken to return to the ground.

Assume that the start velocity is an integer between 1 and 100m/s (inclusive) and that deceleration due to gravity is equivalent -10 m/s^2. Use the equation:

h = u^2 / -2g

where u = start velocity and g = deceleration due to gravity, to calculate the maximum height (h). Use the equation:

t = (4 x h) / u

to calculate total time (t) taken to return to the ground. Output should be accurate to two decimal places.


4.2 Design

TOP DOWN ANALYSIS

The operations identified in the above top level analysis can be combined into the following three procedures/functions.

  1. VERT_MOTION (top level procedure).
    NAMEDESCRIPTIONTYPEVALUE/ RANGE
    START_VELOCITYInput global variableVELOCITY1..100
    DECELERATIONGlobal constantFLOAT-10.0
    MAX_HEIGHTGlobal variableFLOATDefault
  2. MAXIMUM_HEIGHT (level 2 function): Calculate, output and return maximum height of projectile.
    NAMEDESCRIPTIONTYPEVALUE/ RANGE
    START_VELOCITYFormal parameterVELOCITY1..100
    MAX_HEIGHTLocal variableFLOATDefault
  3. TOTAL_TIME (level 2 function): Calculate and output total time.
    NAMEDESCRIPTIONTYPEVALUE/ RANGE
    START_VELOCITYFormal parameterVELOCITY1..100
    MAX_HEIGHTFormal parameterFLOATDefault

The design detail for these procedures/functions is expressed by the set of Nassi-Shneiderman charts given below.

NASSI_SHNEIDERMAN CHART

4.3. Implementation

Commence the implementation with the top top level procedure and only implement the second level using stubs.

-- VERTICAL MOTION
-- 9 September 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure VERT_MOTION is
    subtype VELOCITY is INTEGER range 1..100;
    package INTEGER_INOUT is new INTEGER_IO(INTEGER);
    use INTEGER_INOUT;
    package FLOAT_INOUT is new FLOAT_IO(FLOAT);
    use FLOAT_INOUT;
    START_VELOCITY: VELOCITY;
    DECELERATION: constant := -10.0;
    MAX_HEIGHT: FLOAT;

    ------------------------------------------------------------------------
    -- CALCULATE MAXIMUM HEIGHT
    function MAXIMUM_HEIGHT(START_VELOCITY: VELOCITY) return FLOAT is
    begin
        PUT("In MAXIMUM_HEIGHT function, START_VELOCITY = ");
        PUT(START_VELOCITY);
        NEW_LINE;
        RETURN(1.0);
    end MAXIMUM_HEIGHT;
    ------------------------------------------------------------------------
    -- CALCULATE TOTAL TIME
    procedure TOTAL_TIME(START_VELOCITY: VELOCITY; MAX_HEIGHT: FLOAT) is
    begin
        PUT("In TOTAL_TIME function, START_VELOCITY = ");
        PUT(START_VELOCITY);
        PUT(", MAX_HEIGHT = ");
        PUT(MAX_HEIGHT);
        NEW_LINE;
    end TOTAL_TIME;
    ------------------------------------------------------------------------

-- TOP LEVEL
begin
-- Input start velocity
    PUT_LINE("Input start velocity (integer value between 1 and 100): ");
    GET(START_VELOCITY);
-- Calculate maximum height;
    MAX_HEIGHT := MAXIMUM_HEIGHT(START_VELOCITY);
-- Calculate total time;
    TOTAL_TIME(START_VELOCITY, MAX_HEIGHT);
end VERT_MOTION;

Note that when using subtypes it is sufficient to create an input/output package for the super type (INTEGER or FLOAT as appropriate. We do not need to create individual packages for each subtype.

TEST CASEEXPECTED RESULT
START_VELOCITY
0CONSTRAINT_ERROR
1O.K.
2O.K.
99O.K.
100O.K.
101CONSTRAINT_ERROR

On completion of this first level implementation we should test the operation of the program using (in this case) a set of BVA and limit test cases of the form given to the right. On satisfactory completion this testing stage we can commence the second level implementation.

-- VERTICAL MOTION
-- 9 September 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure VERT_MOTION is
    subtype VELOCITY is INTEGER range 1..100;
    package INTEGER_INOUT is new INTEGER_IO(INTEGER);
    use INTEGER_INOUT;
    package FLOAT_INOUT is new FLOAT_IO(FLOAT);
    use FLOAT_INOUT;
    START_VELOCITY: VELOCITY;
    DECELERATION: constant := -10.0;
    MAX_HEIGHT: FLOAT;

    ------------------------------------------------------------------------
    -- CALCULATE MAXIMUM HEIGHT
    function MAXIMUM_HEIGHT(START_VELOCITY: VELOCITY) return FLOAT is
        MAX_HEIGHT: FLOAT;
    begin
        MAX_HEIGHT := (FLOAT(START_VELOCITY)**2)/(-2.0*DECELERATION);
        PUT("Maximum height reached = ");
        PUT(MAX_HEIGHT, FORE=>4, AFT=>2, EXP=>0);
        PUT(" m");
        NEW_LINE;
        RETURN(MAX_HEIGHT);
    end MAXIMUM_HEIGHT;
    ------------------------------------------------------------------------
    -- CALCULATE TOTAL TIME
    procedure TOTAL_TIME(START_VELOCITY: VELOCITY; MAX_HEIGHT: FLOAT) is
    begin
        PUT("Total time to return to ground = ");
        PUT(4.0*MAX_HEIGHT/FLOAT(START_VELOCITY), FORE=>4, AFT=>2, EXP=>0);
        PUT(" s");
        NEW_LINE;
    end TOTAL_TIME;
    ------------------------------------------------------------------------

-- TOP LEVEL
begin
-- Input start velocity
    PUT_LINE("Input start velocity (integer value between 1 and 100): ");
    GET(START_VELOCITY);
-- Calculate maximum height;
    MAX_HEIGHT := MAXIMUM_HEIGHT(START_VELOCITY);
-- Calculate total time;
    TOTAL_TIME(START_VELOCITY, MAX_HEIGHT);
end VERT_MOTION;

4.4. Testing

TEST CASEEXPECTED RESULT
START_VELOCITYMAX_HEIGHTTotal time
0CONSTRAINT_ERROR
1 0.05 0.20
2 0.20 0.40
99490.0519.80
100500.0020.00
101CONSTRAINT_ERROR

Use BVA (Boundary Value Analysis) and limit testing to analyse and test limits of input variables. Suitable boundary and limit values for START_VELOCITY are 0, 1, 2, 99, 100 and 101. An appropriate set of test cases is given in the table (right).

TEST CASEEXPECTED RESULT
START_VELOCITYMAX_HEIGHTTotal time
50125.0010.00

Use arithmetic testing techniques to test the arithmetic expressions. Test using positive values only in this case (negative and zero values precluded by input type definition in this case). Positive value already included in BVA and limit test cases, however, we should include a test somewhere in the middle of the range

Finally include some data validation test cases.


Example Problem Vertical Motion Report.




Created and maintained by Frans Coenen. Last updated 11 October 1999