INTRODUCTION TO DATA TYPES


1. DATA TYPES

We have seen that the type of a data item defines:

  1. The nature of its internal representation.
  2. The interpretation placed on this internal representation.
  3. As a result of (2) the allowed set of values for the item.
  4. Also as a result of (2) the operations that can be performed on it.

The process of associating a type with a data item is referred to as a data declaration.This binds a data item name to a type definition. (The process of assigning a value to a data item on declaration of that item is referred to as initialisation.)

Ada supports a number of standard basic data types. Two of the most common are:

integer
float

The first defines a data item which can only take integer number values, while the second can only take values which are real (or floating point) numbers. Both have specific storage and interpretation considerations associated with them and both have particular operations associated with them. Note that operations such as + are overloaded there is one plus operation for integer addition and one for real number addition. We can not mix the two - so called mixed mode arithmetic.


2. EXAMPLE PROBLEM CIRCLE CALCULATION


2.1 Requirements

To produce a program that calculates the circumference and area of a circle given its radius. Assume "PI" is equivalent to 3.14 and that the radius is input by the user as a floating point number. Area of a circle = PI x diameter = 2 x PI x radius, and Circumference = PI x radius^2.


2.2 Design

Adopting a top down analysis approach to the above problem:

TOP DOWN ANALYSIS]

we can identify several operations. These operations are simple enough to be wrapped up into a single procedure -

  1. CIRCLE_CALC (top level procedure) - Input radius, and calculate and output circumference and area.

Note that the procedure will need to include definitions for two data items: (1) the constant PI and (2) a variable in which to hold the input. It is a good idea to define the nature of data items required bu a procedure in a tabular format (even if there is only 1) as this information is required for testing purposes:

NAMEDESCRIPTIONTYPEVALUE/RANGE
PIGlobal constantFLOAT3.14
RADIUSGlobal input variableFLOATDefault

NASSI_SHNEIDERMAN CHART

The detailed design for this procedure is given by the N-S chart to the right.


2.3. Implementation

-- CIRCLE CALCULATION
-- 7 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with CS_IO;
use CS_IO;

procedure CIRCLE_CALC is
        PI: constant := 3.14;
        RADIUS: FLOAT;
begin
        PUT_LINE("Input radius: ");
        GET(RADIUS);
-- Calculate circumference using 2xPIxRadius
        PUT("The circumference is: ");
        put(2.0*PI*RADIUS, FORE => 3, AFT => 4, EXP => 0);
        NEW_LINE;
-- Calculate area using PIxRadius^2
        PUT("The area is: ");
        put(PI*RADIUS**2, FORE => 3, AFT => 4, EXP => 0);
        NEW_LINE;
end CIRCLE_CALC;

Some points to note about the above code:


2.4. Testing

TEST CASEEXPECTED RESULT
RADIUSCIRCUMFERENCEAREA
10.062.8000314.0000
0.00.00000.0000
-10.0-62.800031.4000

Arithmetic testing: Test using negative, positive and zero input values for RADIUS as shown in the table (right). Note that when we input a negative number we produce a negative circumference - this is probably not the desired result and thus we should return to the requirements phase and determine what action we should take in the event of a negative radius - (a) error, (b) convert to a positive number, (c) ... ?

Data validation testing: We should also include some tests using input data which id deliberately of the wrong type or to many inputs, no inputs etc.


Example Problem Circle Calculation Report.


3. CATEGORISATION OF TYPES

1.Pre-defined and programmer-defined types. Pre-defined types are types immediately available to the user (they are integral to the language). Programmer-defined types are types derived by the programmer using existing types (pre-defined or otherwise).

2. Scaler and Compound types. Scalar types define data items that can be expressed as single values (e,g. numbers and characters). Compound types (also referred to as composite or complex types) define data items that comprise several individual values. Scaler types are generally pre-defined, while compound types are often programmer-defined.

3. Discrete and Non-discrete types. Discrete (also known as ordinal or linear) types are types for which each value (except its minimum and maximum) has a predecessor and a successor value. The opposite are referred to as non-discrete types.

4. Basic and Higher Level types. Basic types (also referred to as a simple types or type primitives) are the standard scaler predefined types that one would expect to find ready for immediate use in any imperative programming language. Higher level types are then made up from such basic types or other existing higher level types. Higher level types are not necessarily programmer defined - for example many imperative languages include a string high-level type.


4. STANDARD BASIC TYPES

Ada supports a number of standard basic data types:

Data itemEncoding
CharacterCHARACTER
IntegerINTEGER
Real or floating point numberFLOAT
Logical typeBOOLEAN

Note that all of these types are scalar and discrete.


5. EXAMPLE PROBLEM CYLINDER CALCULATION

5.1 Requirements

To produce a program that calculates the surface area and volume of a cylinder given its diameter and height. Assume "PI" is equivalent to 3.14 and that the diameter and height are input by the user as floating point numbers. Area of a cylinder = (2 x AreaOfEnd) + (AreaOfSide) = (2 x PI x (diameter/2)^2) + (height x PI x diameter), Volume of a cylinder = AreaOfEnd x height = (PI x (diameter/2)^2) x height.


5.2 Design

Using a top-down hierarchical decomposition approach we can identify the following, three-level, break-down of operations:

TOP-DOWN DESIGN

From the above we Note that the "calculate area of a circle" operation is repeated. This indicates that the operation would be better placed at a higher level:

TOP-DOWN DESIGN

Inspection of the above thus indicates five distinct operations at three different levels of abstraction. We will address the identified operations using five distinct functions/procedures as follows:

  1. CYLINDER_CALC (Top level procedure): Input data and calls to AREA_OF_CIRCLE, AREA_OF_CYLINDER and VOLUME_OF_CYLINDER.
    NAMEUSAGETYPERANGE
    PIGlobal constantFLOAT3.15
    DIAMETERGlobal variableFLOATDefault
    HEIGHTGlobal variableFLOATDefault
    AREAGlobal variableFLOATDefault
  2. AREA_OF_CIRCLE (level 2 function) - calculate and return area of circle.
    NAMEUSAGETYPERANGE
    RADIUSFormal parameterFLOATDefault
  3. AREA_OF_CYLINDER (level 2 procedure) - calculate and output area of cylinder. Call to CIRCUM_OF_CIRCLE.
    NAMEUSAGETYPERANGE
    DIAMETERFormal parameterFLOATDefault
    HEIGHTFormal parameterFLOATDefault
    AREAFormal parameterFLOATDefault
    CIRCUMLocal variableFLOATDefault
  4. VOLUME_OF_CYLINDER (level 2 procedure) - calculate and output volume of cylinder.
    NAMEUSAGETYPERANGE
    HEIGHTFormal parameterFLOATDefault
    AREAFormal parameterFLOATDefault
  5. CIRCUM_OF_CIRCLE (level 3 function) - calculate and return circumference of circle.
    NAMEUSAGETYPERANGE
    DIAMETERFormal parameterFLOATDefault

The design detail required for each of these procedures is given by the Nassi-Shneiderman charts given below.

NASSI_SHNEIDERMAN CHART

5.3. Implementation

Remember that we implement a top down analysis/design a level at a time commencing with the highest level. Where necessary calls to lower level procedures are implemented using stubs (partial implementations). The top level implementation might be as follows.

-- CYLINDER CALCULATION
-- 4 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure CYLINDER_CALC is
        package FLOAT_INOUT is new FLOAT_IO(FLOAT);
        use FLOAT_INOUT;
        PI                     : CONSTANT FLOAT := 3.14;
        DIAMETER, HEIGHT, AREA : FLOAT;

        ------------------------------------------------------------------
        -- AREA OF CIRCLE function
        function AREA_OF_CIRCLE return FLOAT is
        begin
                PUT_LINE("Area of circle function");
                RETURN(1.0);
        end AREA_OF_CIRCLE;
        ------------------------------------------------------------------
        -- AREA OF CYLINDER procedure
        procedure AREA_OF_CYLINDER is
        begin
                PUT_LINE("Area of cylinder procedure");
        end  AREA_OF_CYLINDER;
        ------------------------------------------------------------------
        -- VOLUME OF CYLINDER procedure
        procedure VOLUME_OF_CYLINDER is
        begin
                PUT_LINE("Volume of cylinder procedure");
        end VOLUME_OF_CYLINDER;
        ------------------------------------------------------------------

-- TOP LEVEL PROCEDURE
begin
-- Input data
        PUT_LINE("Input diameter: ");
        GET(DIAMETER);
        PUT_LINE("Input height: ");
        GET(HEIGHT);
        PUT(DIAMETER);
        PUT(HEIGHT);
        NEW_LINE;
-- Calculation
        AREA := AREA_OF_CIRCLE;
        PUT("Area of circle is: ");
        PUT(AREA,FORE=>3,AFT=>4,EXP =>0);
        NEW_LINE;
        AREA_OF_CYLINDER;
        VOLUME_OF_CYLINDER;
end CYLINDER_CALC;

Some comments:

On completion of this level-1 implementation a test run should be undertaken. Given that we do nothing with the input values at this stage there is no need to use test cases yet. However, we should ensure that the code compiles and, when executed, produces the output we would expect. In the above case the output would be as follows (given diameter and height inputs of 5.0 and 10.0):

kuban-293 $ cylinder_calc
Input diameter:
5.0
Input height:
10.0
 5.00000000000000E+00 1.00000000000000E+01
Area of circle function
Area of circle is:   1.0000
Area of cylinder procedure
Volume of cylinder procedure

We can now proceed to the next level in the implementation. In fact, given that the third level is somewhat trivial, we will implement the second and third levels together:

NESTING OF BLOCKS IN CODE
-- CYLINDER CALCULATION
-- 4 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure CYLINDER_CALC is
        package FLOAT_INOUT is new FLOAT_IO(FLOAT);
        use FLOAT_INOUT;
        PI: CONSTANT FLOAT := 3.14;
        DIAMETER, HEIGHT, AREA: FLOAT;


        -----------------------------------------------------
        -- AREA OF CIRCLE function
        function AREA_OF_CIRCLE(RADIUS: FLOAT)
                        return FLOAT is
        begin
                RETURN(PI*RADIUS**2);
        end AREA_OF_CIRCLE;

        -----------------------------------------------------
        -- AREA OF CYLINDER procedure
        procedure AREA_OF_CYLINDER(DIAMETER, HEIGHT,
                        AREA: FLOAT) is
        CIRCUM: FLOAT;
                ---------------------------------------------
                -- CIRCUMFERENCE OF CIRCLE function
                function CIRCUM_OF_CIRCLE (DIAMETER:
                                FLOAT) return FLOAT is
                begin
                        RETURN(PI*DIAMETER);
                end CIRCUM_OF_CIRCLE;
                ---------------------------------------------
        begin
                CIRCUM:= CIRCUM_OF_CIRCLE(DIAMETER);
                PUT("Area of cylinder is: ");
                PUT(AREA*2.0+CIRCUM*HEIGHT,FORE=>3,
                                AFT=>4,EXP =>0);
                NEW_LINE;
        end  AREA_OF_CYLINDER;

        -----------------------------------------------------
        -- VOLUME OF CYLINDER procedure
        procedure VOLUME_OF_CYLINDER(HEIGHT, AREA: FLOAT) is
        begin
                PUT("Volume of cylinder is: ");
                PUT(AREA*HEIGHT,FORE=>3,AFT=>4,
                                EXP =>0);
                NEW_LINE;
        end VOLUME_OF_CYLINDER;
        -----------------------------------------------------


-- TOP LEVEL procedure
begin
-- Input data
        PUT_LINE("Input diameter: ");
        GET(DIAMETER);
        PUT_LINE("Input height: ");
        GET(HEIGHT);
-- Calculation
        AREA := AREA_OF_CIRCLE(DIAMETER/2.0);
        AREA_OF_CYLINDER(DIAMETER, HEIGHT, AREA);
        VOLUME_OF_CYLINDER(HEIGHT, AREA);
end CYLINDER_CALC;

Some points to note about the above code:

  1. Formal parameters have been included in the above procedures and functions describing variables that are also available globally. This is considered good programming practice as it guards against accidental changes to the values for global variables and ensures that individual procedures and functions have a "stand alone" capability.
  2. A formal parameter (RADIUS: FLOAT) has been included in the AREA_OF_CIRCLE procedure. Note that when the procedure is called from lower down in the program the actual parameter is the expression DIAMETER/2.
  3. The nesting of the various functions and procedures is illustrated in the diagram to the right.
  4. The operator ** is the exponential operator.
  5. In the statement PUT(AREA*2+CIRCUM*HEIGHT,FORE=>3,AFT=>4,EXP =>0) the mathematics operators have the usual precedence, i.e. multiplication is implemented before addition (more on this later).
  6. Remember that Ada does not support mixed-mode arithmetic therefore we cannot write AREA*2+CIRCUM*HEIGHT, but must write AREA*2.0+CIRCUM*HEIGHT.

TEST CASEEXPECTED RESULT
DIAMETERHEIGHTAREAVOLUME
0.00.00.00000.0000
0.010.00.00000.0000
0.0-10.00.00000.0000
5.00.039.25000.0000
5.010.0196.2500196.2500
5.0-10.0-117.7500-196.2500
-5.00.0-39.25000.0000
-5.010.0-117.75196.2500
-5.0-10.0196.2500-196.2500

5.4. Testing

Arithmetic testing Test using all possible combinations of negative, positive and zero input values for the DIAMETER and HEIGHT user inputs as shown in the given table (right). Note that the code allows input of negative numbers. This is likely to be undesirable and thus a return to the requirements specification should be instigated and adjustments made in the light of the procurers wishes with respect to negative results.

Data validation testing Provide input data with incorrect syntax, both blatant and subtle. Suggested test cases given below. The '*' symbol indicates that we do not expect to input a second value as we expect the code to fail.


TEST CASEEXPECTED RESULT
DIAMETERHEIGHTAREAVOLUME
5*FLOAT_INPUT_ERROR_PERIOD_NOT_READ
5.e*FLOAT_INPUT_ERROR_PERIOD_NOT_READ
5.010FLOAT_INPUT_ERROR_PERIOD_NOT_READ
5.01e.0FLOAT_INPUT_ERROR_PERIOD_NOT_READ

Example Problem Cylinder Calculation Report.




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