Lesson 5
Functions and Procedures
Functions and Procedures are also known as subroutines or subprograms.
Both are like mini-programs in that they contain their own constants, variables, data types, procedures and function.
The use of subroutines is based on the divide and conquer technique, where a large program is broken down into several smaller parts so that it can be completed faster and more effectively.
The advantages of using subroutines include:
Syntax for Procedures:
PROCEDURE
ProcName [ ( formal parameters ) ];{ declaration section }
BEGIN
{ executable statements }
END;
Syntax for Functions:
FUNCTION
FuncName [ ( formal parameters ) ] : FuncType;{ declaration section }
BEGIN
{ executable statements }
END;
Note:
Procedures.
Program 5-1
program
ProcedureSayHelllo;uses CRT;
var
Sum : integer;
Num : integer;
procedure SayHello;
begin
WriteLn(‘Hello’);
end;
begin
SayHello;
end.
Program 5-2
program
TestProcedure1;uses CRT;
var
Sum : integer;
Num : integer;
procedure Sum10Numbers;
var
I : integer;
begin
Sum := 0;
for I := 1 to 10 do
begin
Write('Enter num : ');
ReadLn( Num );
Sum := Sum + Num;
end;
end; { Sum10Numbers }
begin { main program }
ClrScr;
Sum10numbers; { call procedure SUM10NUMBERS }
WriteLn;
WriteLn('Sum of 10 numbers is ', Sum );
ReadLn;
end. { main program }
Note:
To call a subroutine just specify the subroutine name.
Scope Rules
Fundamental Scope Rule
The scope of an entity is the program or subprogram in which it is declared.
Scope Rule 1
An item declared within a procedure or function is not accessible outside the procedure or function.
Scope Rule 2
A global entity is accessible throughout the main program and in any subprogram in which no local entity has the same name as the global item.
Scope Rule 3
An entity declared in a subprogram can be accesses by any subprogram defined within it, provided that no entity with the same name is declared in the subprogram itself.
Scope Rule 4
If SubA and SubB are subprograms defined in the same program or subprogram and if SubA is referenced by SubB, then SubA must be defined before SubB.
Global And Local Identifiers.
Local identifiers are the variables declared within the subroutine.
|
Global identifiers, on the other hand, are the identifiers declared in the main program block.
|
Local identifiers can only be used by the subroutine which it is in. It cannot be used in the main program or other subroutines.
|
Global identifiers can be used throughout the whole program. These are known as the scope of identifiers.
|
This program demonstrates local and global identifiers.
program GlobalLocal;
var
A, B, C : integer; { global variables }
procedure Local;
var
A, D, E : integer; { local variables }
begin
A := 10; D := 20; E := 30;
WriteLn( A:4, B:4, C:4, D:4, E:4 );
end;
begin { main program }
A := 100; B := 200; C := 300;
WriteLn( A:4, B:4, C:4 );
Local;
WriteLn( A:4, B:4, C:4 ); ReadLn;
end. { main program }
Note:
The value of the variable A does not change in the main program although it has been assigned a new value in the procedure. This is because A is also a local variable to the procedure and it's value is stored in a different memory location.
Parameter Passing.
Parameters give the procedure or function the flexibility to process different values each time it is called.
Let's look at MS-DOS for a moment. Take the example of the COPY command.
COPY A:*.* B: copies all files from drive A to B
COPY C:\PASCAL\ B: copies all files from the subdirectory PASCAL to drive B
The parameters A:*.*, B: and so on, instructs the COPY command to copy files from one area to another. Without these parameters (or arguments) the copy command would not be so versatile or useful. Imagine a command which only allows you to copy from drive A to drive B and nowhere else. It would be very difficult if we want to copy something to or from drive C.
When passing parameters, there are several rules which must be followed:
All parameters are passed according to the location they are placed in the parameter list, whether we are talking about formal or actual parameters. If you want an actual parameter to be passed to a certain formal parameter, you must make sure that you place the parameter at the correct position where you want the actual parameter to be received by the formal parameter.
Pass By Value And By Reference.
Looking at the example you will see that the parameters A and B are passed to W and X. This is determined by the location in which the parameters are placed. These parameters are passed by value. This means that the values in variables A and B will be assigned to the parameters W and X. W and X will have separate memory locations to store the values which are received from A and B.
Parameters C and D are passed by reference to the variables Y and Z. It means that the variables Y and Z share the same memory location as C and D. Therefore, if the values of Y and/or Z is changed in any way in the procedure, so will the values of C and D.
The use of value parameters is for the subroutine to handle different values and ignore any changes done to the parameter after the subroutine call is completed. When a parameter is passed by value, the formal parameter just receives the value and there is no more relation between the actual and formal parameters. The subroutine can then execute according to the parameter passed.
When passing parameters by reference, the formal and actual parameters will maintain a constant link until the procedure call is completed. This means, if the value of the formal parameter changes, the value of the actual parameter will also change.
Parameter passing by value is used when we want to maintain the value of the actual parameter even if the value is changed by the subroutine. This is because the values in a subroutine will be destroyed after the subroutine call is completed.
Here is another program where passing parameters would be more useful.
program
UseParameters;uses CRT;
var
Num : integer;
S : string;
procedure GetInteger ( var Num : integer );
var
StrNum : string;
ErrPos : integer;
begin
repeat
ReadLn( StrNum );
val( StrNum, Num, ErrPos );
until ErrPos = 0;
end; { GetValidInteger }
procedure UpperCase ( var S : string );
var
I : integer;
begin
for I := 1 to length( S ) do
S[ I ] := upcase( S[ I ] );
end; { UpperCase }
begin { main program }
ClrScr;
Write('Type in an integer : ');
GetInteger( Num );
WriteLn('Integer : ',Num );
Write('Type in a sentence : ');
ReadLn( S ); UpperCase( S );
WriteLn('Capitals : ', S );
ReadLn;
end. { main program }
Functions.
Functions are similar to procedures in every way except the function name is used to reference to more than a block of code. It also references a variable.
The passing of parameters, local & global identifiers, and the subroutine block is the same for functions and procedures except the keyword used to declare them and a type which must be specified with the function name.
Let's have a look at a program which uses functions.
program
UseFunctions;uses CRT;
var
Num1, Num2 : integer;
Pw1, Pw2 : real;
Facto1, Facto2 : integer;
function Power ( X,Y : integer ) : real;
begin
Power := exp( ln(X) * Y );
end; { Power }
function Factorial ( X : integer ) : integer;
var
Facto, I : integer;
begin
Facto := 1;
for I := 1 to X do
Facto := Facto * I;
Factorial := Facto;
end; { Factorial }
begin { main program }
ClrScr;
Write('Type in 2 integers : ');
ReadLn( Num1, Num2 );
Pw1 := Power( Num1, Num2 );
Pw2 := Power( Num2, Num1 );
Facto1 := Factorial( Num1 );
Facto2 := Factorial( Num2 );
WriteLn( Num1,' to the power of ',Num2,' = ', Pw1:0:0);
WriteLn( Num2,' to the power of ',Num1,' = ', Pw2:0:0 );
WriteLn('Factorial of ',Num1,' is ',Facto1 );
WriteLn('Factorial of ',Num2,' is ',Facto2 );
ReadLn;
end. { main program }
In this program, two functions are used. The function POWER is used to determine the power of a number to another, and FACTORIAL is used to determine the factorial of a number. If you notice the way a function is called and used, it is different from procedures.
Function names references to variables and therefore when a value is assigned to the function name in the function body, the value goes to this variable. Once there is a value in any variable, this value cannot be 'left alone'. The value has to be 'used', one way or another.
Consider these statements:-
var
A : integer;
begin
A;
end.
The variable A cannot be considered a statement in the program. The compiler just won't take A as a statement.
This applies to functions too. Therefore, after a call to a function is made, you must make sure that the value returned from the function is 'used'.
This can be done by:-
Pascal compilers won't allow any values to be assigned to functions outside the function's statement body. The types of data which the function can return is limited to simple types only. Structured types are not allowed. You will see the difference between simple and structured types in later lessons.
Functions are mostly used to solve mathematical problems. When a result is needed to be returned through an identifier, a function should be used. There are already some functions in Pascal which you might have used. Look for those 'commands' which are used in conditions, those 'commands' which are assigned to variables etc. These are all the standard functions built in to Pascal.
Programmers sometimes use 'empty' subroutines or dummy stubs in order to test a completed part of a program. The completed part of the program might have to use several subroutines, but these subroutines do not yet contain anything meaningful in them.
Here is an example:-
program
UseStubs;uses CRT;
var
Choice : char;
procedure AddNewRecord;
begin
WriteLn('Executing ADDNEWRECORD.');
end; { AddNewRecord }
procedure DisplayRecord;
begin
WriteLn('Executing DISPLAYRECORD.');
end; { DisplayRecord }
procedure DeleteRecord;
begin
WriteLn('Executing DELETERECORD.');
end; { DeleteRecord }
begin
{ main program }
repeat
ClrScr;
WriteLn(' Main Menu. ');
WriteLn(' ~~~~~~~~~~ ');
WriteLn('1. Add New Record. ');
WriteLn('2. Delete Record. ');
WriteLn('3. Display Records.');
WriteLn('4. Quit Program. ');
Write('Enter Choice : ');
ReadLn( Choice );
case Choice of
'1' : AddNewRecord;
'2' : DeleteRecord;
'3' : DisplayRecord;
else if Choice <> '4' then
WriteLn('Wrong Choice.');
end; { case Choice }
ReadLn;
until Choice = '4';
end. { main program }
This is not a complete program, as you can see, because the procedures ADDNEWRECORD, DELETERECORD and DISPLAYRECORD do not actually have a proper statement body to carry out the task which they are supposed to do. These stubs are therefore used only to test the completed part of the program, which is the main program. You can see that the main program consists of calls to those procedures mentioned earlier.
Overall, procedures and functions are used to enhance program readability, maintainability and simplify documentation. It also provides a chance to test the program without completing the whole program yet, by referring to them as dummy stubs.