PROGRAM COMPOSITION


1. OVERVIEW

We can distinguish four levels of programme hierarchy:


2. BLOCKS


3. Procedures and Functions

The distinction between a procedure and a function is that a function returns a value while a procedure does not.

A procedure or function comprises a head and a body. In the head the name of the routine and its formal parameters are specified. The code is defined in the body. In addition, in the case of a function, the function declaration must include a definition for its return value.

The format for declaring a procedure is as follows:

procedure NAME `(' <ARGUMENTS> `)' is
        begin
                <BODY>
        end NAME `;'

While that for a function declaration is:

function NAME `(' <ARGUMENTS> `)' return T is
        begin
                  <BODY>
        end NAME `;'

where T is the type of the data item to be returned. Note also that a procedure (function) does not have to have any arguments. Further discussion concerning formal parameters for procedures and functions will be presented later.


3.1. Routine Invocation

Functions and procedures are activated by a procedure or function call (routine invocation) which names the routine and supplies the actual parameters. Note that after invocation control is returned to the point immediately after the invocation as illustrated in the following diagram.

Routine invocation

4. ROUTINES

One of the most important issues that has to be addressed in the design of a programming language is the support it gives to the control of complexity. An important technique is the division of a program into "chunks" called routines (or sub-programs) that will allow the programmer to think at a more abstract level. At its simplest a routine may comprises a single procedure or function (i.e a routine can be equivalent to a block). More often it comprises a group of (in Ada nested) procedures and/or functions invoked through routine invocation.

By adopting a top-down hierarchical decomposition to problem analysis and design we can identify the routines we require.


5. MODULES

A number of declarations of types, variables and sub-routines can be grouped together into a module or package (also sometimes referred to as a task). The concept of modules (and modular programming) appeared in 1970's in response to the increasing size of programs. The use of modules provides convenient access to existing resources, and consequently results in more time efficient programming. Modules comprise a specification part and a body part. The specification part contains a description of the interface and the body the code that implements the interface. The specification part is accessible to the user, the implementation part is "hidden" (information hiding).

6. PROGRAMS

The highest level of program hierarchy is the program.

Ada assumes that there exists a method outside the language which allows the programmer to specify the name of a procedure and which will then construct an executable binary program for that procedure containing all the necessary modules.


7. EXAMPLE PROBLEM GIANT ADA


7.1. Requirements

To write the word "Ada" vertically down the screen using giant letters made up of strings of * (asterisk) characters and blank spaces as follows:

GIANT LETTERS

7.2. Design

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

TOP-DOWN DESIGN

Note that the "Draw giant letter A" operation is repeated twice. Therefore we only need three procedures as follows:

  1. GIANT_ADA (top level procedure): Calls to GIANT_A and GIANT_D procedures.
  2. GIANT_A (level 2 procedure): Draw giant letter A.
  3. GIANT_D (level 2 procedure): Draw giant letter D.

The design detail required for each of these procedures is given by the Nassi-Shneiderman charts given below. Note how routine invocation is indicated in the top level chart using the routine name surrounded by an ellipse.


NASSI_SHNEIDERMAN CHART

7.3. Implementation

To implement a top down design comprising more than one level we commence by encoding the top level first, testing this, and then implementing the lower levels, level by level, testing each level of implementation as it is completed. Where necessary lower level procedures can be indicated using "stubs". Thus, in this case, implementation will commence by writing a top-level procedure as follows:

NESTING
-- GIANT ADA
-- 9 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with CS_IO;
use CS_IO;

procedure GIANT_ADA is

        -------------------------------------------
        -- GIANT LETTER A PROCEDURE
        procedure GIANT_A is
        begin
                PUT_LINE("GIANT_A");
        end GIANT_A;

        -------------------------------------------
        -- GIANT LETTER D PROCEDURE
        procedure GIANT_D is
        begin
                PUT_LINE("GIANT_D");
        end GIANT_D;
        -------------------------------------------

-- TOP LEVEL PROCEDURE
begin
        GIANT_A;
        GIANT_D;
        GIANT_A;
end GIANT_ADA;

Inspection of the above code indicates the nesting illustrated to the right. Note the ordering of the procedure declarations - this governs the visibility of procedures (i.e. which procedure can be used by which other procedure). For example in the above case the GIANT_D procedure is not visible form the GIANT_A procedures although the GIANT_A procedure is visible from the GIANT_D procedure. This is a direct consequence of the ordering in which these procedures are declared. Note also that it is considered good programming practice to demarcate procedures using (say) a dashed line and to introduce each procedure with a short comment. This is intended to enhance clarity and hence readability. On completion of this first level in the top-down design the code written so far should be tested. In this case a single execution of the program so far will suffice. We would expect the output to be as follows:

GIANT_A
GIANT_D
GIANT_A

The second level in the top-down design can now be encoded as follows:

-- GIANT ADA
-- 9 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with CS_IO;
use CS_IO;

procedure GIANT_ADA is

        -----------------------------------------------------
        -- GIANT LETTER A PROCEDURE
        procedure GIANT_A is
        begin
                PUT_LINE("      *");
                PUT_LINE("     * *");
                PUT_LINE("    *   *");
                PUT_LINE("   *     *");
                PUT_LINE("  *********");
                PUT_LINE(" *         *");
                PUT_LINE("*           *");
                NEW_LINE;
        end GIANT_A;
        -----------------------------------------------------
        -- GIANT LETTER D PROCEDURE
        procedure GIANT_D is
        begin
                PUT_LINE("  *******");
                PUT_LINE("  *      *");
                PUT_LINE("  *       *");
                PUT_LINE("  *       *");
                PUT_LINE("  *       *");
                PUT_LINE("  *      *");
                PUT_LINE("  *******");
                NEW_LINE;
        end GIANT_D;
        -----------------------------------------------------

-- TOP LEVEL PROCEDURE
begin
        GIANT_A;
        GIANT_D;
        GIANT_A;
end GIANT_ADA;

7.4. Testing

On completion of the implementation phase the entire program should be tested. In this case, given that there is no input and a straight forward sequence of commands, final testing can be carried out through a single execution of the program. The expected result of this final test would be as follows:

      *
     * *
    *   *
   *     *
  *********
 *         *
*           *

  *******
  *      *
  *       *
  *       *
  *       *
  *      *
  *******

      *
     * *
    *   *
   *     *
  *********
 *         *
*           *

Example Problem Giant Ada Report.




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