Back

Subroutines, variables and parameters

Introduction
A subroutine is just a self-contained block of code that carries out a specific task. Functions and procedures are examples of subroutines. A good procedural program design will generally consist of many procedures and functions. These will then be called in turn by a main program. We saw the shape of a well-designed program in an earlier section. We can see the outline again in the next diagram, with an alternative way of viewing the program. Notice that the main program is in fact very simple, consisting only of calls to procedures.

sub

The difference between procedures and functions
Both of these programming units are broadly similar. They are both modules of code. They can both accept parameters (pieces of data that are passed to it when they are called), both can do calculations on data and both can return values that can be used by the main program. Functions, however, traditionally return only a single value to the main program. In addition, this value is passed back to the main program using a variable that has the same name as the function! Just to confuse things, however, some languages like Python can return multiple values using functions. We will stay with the traditional view for the moment.

If that is difficult to get your head around, look at the recursion example in the next chapter. Each time a function call ended, a single value was passed back to where the function was called from. The value was passed back using a variable called Fact. This variable had the same name as the actual function itself. Procedures can also pass back values but they could also pass no values back at all, or just one value, or many values. Functions only pass back one value using a variable that is the same name as the function itself.

Variables
A variable is a name given to a particular memory location, a location in RAM. By using variables, a programmer can refer to it to store and retrieve data, even though they may not even know what data is in that location! For example, a programmer can use the instruction:

PRINT Result

The variable name is ‘Result’. ‘Result’ actually refers to a RAM location and in that location is a piece of data. Even though the programmer doesn’t know what data is being held there, they can still print it out, by using the instruction just given. High-level languages make a lot of use of variables. It means that the programmer doesn’t have to concern itself with actual memory addresses, only the names of RAM addresses! By using meaningful names, the programmer can write programs that can easily be followed and understood.

Every variable in a program must be ‘declared’. That means that the programmer must state in the program what kind of data type that particular variable will hold. Then, when the translator comes to translate the program, they will know how much RAM to reserve for that variable - different data types require different amounts of RAM to hold the actual data item.

Variables can be declared in one of two places. They can be declared at the very beginning of a program or they can be declared within a particular function or procedure. If a variable is declared at the beginning of a program then that variable is available to all the functions and procedures that need to use it throughout the entire program. If it is declared in a particular function or procedure then it is available only in that module. This may seem confusing so before we discuss the scope of a variable, study the following example!

An example of an outline program

Program Wages
Var {declare global variables here} // declare the global variables here, at the beginning of the program.

Procedure CalculatePay
     Var {Declare local variables here} // declare the local variables for the procedure CalculatePay here.
Begin

End;

Procedure CalculateBonus
     Var {Declare local variables here} // declare the local variables for the procedure CalculateBonus here.
Begin

End;

Procedure CalculateDeductions
     Var {Declare local variables here} // declare the local variables for the procedure CalculateDeductions here.
Begin

End;

Begin {This is the main program}
     Procedure CalculatePay;
     Procedure CalculateBonus;
     Procedure CalculateDeductions;
End.

We have said that variables can be declared in one of two places.

    1. At the beginning of the program.
    2. Within in a function or procedure. 

The scope of a variable
Some variables need to be available in more than one procedure. For example, in the above wages program example, you may need a variable called HoursWorked in the two procedures CalculatePay and CalculateBonus. Both procedures may need to retrieve this information. Because HoursWorked is needed in more than one procedure, it should be declared in the main program section. When you declare a variable in this position so that it is available to any procedure or function in the program then it is known as a global variable.

Some variables are only required in a particular procedure or function. The most obvious example of a variable needed within a particular module of code but not anywhere else is a counter. For example, in the CalculateDeductions procedure, you may have the following iteration:

FOR COUNT = 1 to 10 DO
BEGIN
     ----------------
     ----------------
     ----------------
END.

COUNT is an example of a variable that should be declared only within the procedure CalculateDeductions. Variables declared within a module are known as local variables. Unlike global variables, the data they hold are not available to other modules. Whether a variable is available locally or globally is sometimes referred to as the ‘scope’ of the variable.

Why use local variables?
Because one of the aims of modular programming is to produce self-contained modules that can be tested on their own, (and contribute towards a library of modules) it is a good idea to use local variables wherever possible. They help to ensure that modules are indeed standalone because the variables cannot have an effect on other modules in the program. This is one of the main weaknesses of procedural programming languages. One module can be unintentionally affected by what happens in other modules because of the way global variables are used.

Passing parameters
If you write a program as a set of procedures and functions, how can you pass data to them so they can work on it? This is done using 'parameter passing'. The passing of parameters encourages good program design. Since there is now a method that allows independent modules to communicate with each other, we are in a position to write as many independent modules as we like! That means that we could have lots of different people writing modules of code and then simply connect the modules together. It also allows us to start building libraries of modules.

Consider the procedure CalculatePay given in the example earlier. This procedure will calculate the pay for an individual based upon the number of hours they work. If you want to work out the pay for someone, you must call the procedure, telling it what number of hours you want it to work with. To be able to do this you need to:

    1. set up the procedure to accept the number of hours
    2. call the procedure with the hours someone has worked.

You might write the procedure something like this:

Procedure CalculatePay (Hours:integer)
Rate := 5
Begin
     Pay := Rate * Hours
End

‘Hours:integer' is known as the formal parameter. Formal parameters define what data the procedure needs to receive so that the procedure can actually work. Formal parameters don't tell the procedure what actual data to use. They only define what data the procedure must get so that it can work! The first line in this procedure,

Procedure CalculatePay (Hours:integer)

is saying that when the procedure CalculatePay is called, it needs to be given an integer value. That integer value will then be assigned to the variable name Hours.
For example, if you wanted to calculate the pay for someone who has worked 10 hours, then you would need to call the procedure with the value 10, like this:

CalculatePay (10)

This calls the procedure CalculatePay and passes to it the actual parameter to use - in this case 10. It is also commonly known as the argument. The variable Hours would then be assigned the value 10.

You should see now that a programmer could write a standalone procedure called, for example, CalculateTax. They could set up the procedure with two formal parameters, perhaps called AmountPaid and TaxRate. If this procedure was put into a library then anyone who needs to write a program that does a tax calculation can simply use this procedure - they don't have to write a completely new one from scratch. They simply put the procedure into their program and call it with the necessary arguments.

Of course, we have only passed parameters into a procedure in these examples. We may also need to pass parameters out of the procedure as well. There would be little point in having a procedure that can accept values and calculate somebody’s pay, if we then couldn’t pass that value out to the main program so a different module of code can use it!

In the previous pay example, we saw that the first line of the procedure was:

Procedure CalculatePay (Hours:integer)

If we wanted to pass a value out of this procedure, perhaps called Pay, then we would need to modify this line:

Procedure CalculatePay (Hours:integer; var Pay:real)

When the CalculatePay procedure has finished, the main program can use the value that it finds in the variable called Pay. Another procedure could refer to this variable if it needs to use the value held in it. Because other procedures can refer to it, this type of parameter is known as a variable parameter. When the CalculatePay procedure calculated somebody’s pay, it passed the pay back using a variable. We can say that it passed the number back using a reference to a variable.

Back