Time for a break! We can distinguish four levels of programme hierarchy:
Two other possible ingredients, which should be discussed here, are Generics and Abstract Data Types (ADTs).
Choose a mug: (1) Blocks, (2) Routines, (3) Modules and Packages, (4) Programs, (5) Generics, or (6) Abstract Data Types (ADTs).
Scope rules govern the visibility of data items (i.e. the parts of a program where they can be used). They also bind names to types. Where this is determined at compile time this is called static scoping. The opposite is dynamic scoping. Dynamic scoping is generally a feature of logic languages such as PROLOG and functional languages such as LISP. The advantages of static scoping is that it allows type checking to be carried out at compile time. Most imperative languages use static scoping.
Generally speaking, in imperative languages, the scope of a declaration commences at the end of the declaration statement and continues to the end of the block.
The scope of a data item in C is governed by its storage class. Generally data items belong to one of two storage classes:
C also supports two other storage classes static and register, but these will not be discussed further here.
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 can be equivalent to a block. More specifically a routine can be defined as a collection of declarations and statements that must be invoked explicitly (routine invocation). Note that after invocation control is returned to the point immediately after the invocation. An additional advantage is that routines can be stored in libraries for reuse.
Further Issues involved include:
These will be discussed later. It should also be noted that although the concepts remain the same routines or subprograns are referred to by different names in different languages. In C routines are referred to as functions. In Pascal and Ada they are called procedures and functions. Modula-2 names them procedures (even if some of them are actually functions). COBOL uses the terms paragraphs, while FORTRAN and BASIC refer to them as sub-routines and functions.
We can identify two types of routine:
The distinction between a procedure and a function is that a function returns a value while a procedure does not. A function declaration must therefore be called as part of an assignment expression and incorporate a definition for its return value. Some imperative languages (Ada, FORTRAN, Pascal) make a clear distinction between procedures and functions. Other imperative languages (C, ALGOL 68) do not.
A procedure (function) comprises a head and a body. In the head the name of the routine and its formal parameters are specified. In the body the necessary code is given.
Functions and procedures are activated by a procedure or function call which names the routine and supplies the actual parameters. Most imperative languages (Ada and C included) use positional parameters. Examples:
AVERAGE:= MEAN_VALUE(4.2, 9.6); (Ada)
average = meanValue(4.2, 9.6); (C)
Alternatives include keyword or default parameters.
In block structured languages the order in which procedures are declared also effects visibility. Ada (and other block structured languages such as Pascal) requires that any use of an identifier must be preceded by its declaration. Thus if two procedures are declared at the same level, their order of declaration will dictate "who can call whom". The procedure currently being declared cannot see any following procedures. In Ada this can be overcome by using an incomplete declaration. Ordering of procedure declarations is not significant in C.
with CS_IO ; use CS_IO ; procedure PROC_EXAMPLE is NUM_X, NUM_Y: float; procedure MEAN_VALUE (VALUE_1, VALUE_2: float) is begin put("MEAN VALUE PROCEDURE"); new_line; put("===================="); new_line; put("The mean is "); put((VALUE_1+VALUE_2)/2.0); new_line; end MEAN_VALUE; begin get(NUM_X); get(NUM_Y); MEAN_VALUE(NUM_X,NUM_Y); end PROC_EXAMPLE;
with CS_IO ; use CS_IO ; procedure FUNC_EXAMPLE is NUM_X, NUM_Y, NUM_Z: float; function MEAN_VALUE (VALUE_1, VALUE_2: float) return float is begin put("MEAN VALUE FUNCTION"); new_line; put("===================="); new_line; return (VALUE_1+VALUE_2)/2.0; end MEAN_VALUE; begin get(NUM_X); get(NUM_Y); Z:= MEAN_VALUE(NUM_X,NUM_Y); put("The mean is "); put((NUM_X+NUM_Y)/2.0); new_line; put("The mean is "); put(Z); new_line; end FUNC_EXAMPLE;
#include <stdio.h> void meanValue(float, float); void main(void) { float num_x, num_y; scanf("%f%f",&num_x,&num_y); meanValue(num_x,num_y); } void meanValue(float value1, float value2) { printf("MEAN VALUE PROCEDURE\n"); printf("====================\n"); printf("\nThe mean is %f\n",(value1+value2)/2.0); }
#include <stdio.h> float meanValue(float, float); void main(void) { float num_x, num_y; printf("Enter 2 real numbers "); scanf("%f%f",&num_x,&num_y); printf("MEAN VALUE FUNCTION\n"); printf("===================\n"); printf("\nThe mean is %f\n",meanValue(num_x,num_y)); } float meanValue(float value1, float value2) { return((value1+value2)/2.0); }
A number of related declarations of types, variables and routines can be grouped together into a module, also sometimes referred to as a package (Ada) or task. The concept of modules (and modular programming) appeared in 1970's in response to the increasing size of programs. 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).
Ada packages comprise two parts:
Note that the body is not visible to the user.
Creating the package:
package TIMES_TWO_PKG is -- SPECIFICATION function TIMES_TWO ( NUMBER : integer ) return integer; end TIMES_TWO_PKG ; -- BODY package body TIMES_TWO_PKG is function TIMES_TWO ( NUMBER : integer ) return integer is begin return(NUMBER*2); end ; end TIMES_TWO_PKG;
Incorporating the package into another program:
with CS_IO, TIMES_TWO_PKG; use CS_IO ; procedure EXAMPLE is VALUE: integer:= 4; DOUBLE: integer:= 0 ; begin DOUBLE := TINESTWO.TIMES_TWO(VALUE); put("VALUE = "); put(VALUE); new_line; put("DOUBLE = "); put(DOUBLE); new_line; end EXAMPLE;
Compiling:
ICC timestwo.ada
Creating the module:
/* SPECIFICATION */ int timesTwo(int); /* BODY */ int timesTwo(int value) { return(value*2); }
Incorporating the module into another program:
#include <stdio.h> void main(void) { int value=4; printf("Two times %d = %d\(n",value,timesTwo(value)); }
Compiling:
cc -Aa -c timestwo.c cc -Aa -c example.c cc -Aa -o example example.o timestwo.o
Whereas a C module is first compiled to create an object file (a .o file) and later linked into the main program, a header file is compiled at the same time as the "main" program. The sequence of activities is as follows - first create a .h file:
int timesTwo(int); int timesTwo(int x) { return(x*2); }
Second, incorporate the .h file into a program:
#include <stdio.h> #include "timestwo.h" void main(void) { int x=4; printf("Two times %d = %d\n", x,timesTwo(x)); }
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.
C assumes that the programmer will specify all necessary user object files in a specialised invocation of the system linker. This invocation searches the object files for a routine with the fixed external name main and constructs an executable binary program which, when called, will execute the routine main.
Don't forget to wash your mug! Hot tap: return to imperative home page, Cold tap: proceed to parameter passing.
Created and maintained by Frans Coenen. Last updated 03 July 2001