PROCEDURES AND FUNCTIONS
A PASCAL PROGRAM OUTLINE
In order to properly define procedures and functions we need to lay some groundwork in the form of a few definitions. These are important concepts, so pay close attention. Every Pascal program is composed of three fundamental parts which can be defined as follows.
It is very important that you grasp the above definitions because we will be referring to them constantly during this chapter and throughout the remainder of this tutorial. With that introduction, let's go on to our first Pascal program with a procedure in it. In fact, it will have three procedures.
THE FIRST PROCEDURES
Example program ------> PROCED1.PAS
Examine PROCED1.PAS as your first example program with a procedure and display it on your monitor. You will notice that it doesn't look like anything you have seen up to this point because it has procedures in it. Let's go back to our definitions from above. The first line is the Program Heading which should pose no difficulty. The Declaration Part begins with the var statement in line 4 and continues down through and including all three procedures ending in line 19. Lines 21 through 26 constitute the Statement Part. It may seem strange that what appears to be executable Pascal statements, and indeed they are executable statements, are contained in the Declaration Part rather than the Statement Part. This is because of the Pascal definition and it will make sense when we have completed our study of procedures and functions.
Continuing to examine PROCED1.PAS, we will make note of the program itself, which is the Statement Part. The program, due to the nature of Pascal and the carefully chosen procedure names, clearly tells us what it will do. It will write a header, eight messages, and an ending. The only problem we are faced with is, how will it write these messages? This is where the Declaration Part is called upon to define these operations in detail. The Declaration Part contains the three procedures which will completely define what is to be done by the procedure calls in the main program.
DEFINITIONS GO IN THE DEFINITION PART
It should be clear to you that the definitions of the procedures should be in the Definition Part of the program because that is exactly what they do. In the case of a var, a variable is defined for later use by the main program, and in the case of a procedure, the procedure itself is defined for later use by the main program.
Let's arbitrarily pick one of the procedures, the first, and examine it in detail. The first executable statement we come to in the main program is line 22 which says simply, Write_A_Header, followed by the usual statement separator, the semicolon. This is a simple procedure call. When the compiler finds this statement, it goes looking for a predefined procedure of that name which it can execute. If it finds one in the Declaration Part of the program, it will execute that procedure. If it doesn't find a user defined procedure, it will search the Pascal library for a system defined procedure and execute it. The Write and Writeln statements are system procedures, and you have already been using them quite a bit, so procedures are not completely new to you. If the compiler doesn't find the procedure defined in either place, it will generate an error message. Depending on which version of TURBO Pascal you are using, the system may search several libraries to find the procedures called by the program. Much more will be said about this later in this tutorial.
HOW TO DEFINE & CALL A PROCEDURE
To call a procedure, we simply need to state its name. To define a simple procedure, we use the reserved word procedure followed by its calling name, with a semicolon as a terminator. Following the Procedure Heading, there is the Declaration Part of the procedure followed by a body which is nothing more than a compound statement bracketed by the reserved words begin and end. This is identical to the Statement Part of the main program except that the procedure ends with a semicolon instead of a period. Any valid Pascal statements can be put between the begin and end, and in fact, there is no difference in what can be put in a procedure and what can be put in the main program.
The program we are examining would be no different if we would eliminate the first procedure completely and move the Writeln contained in it down to the Statement Part in place of Write_A_Header. If that statement is not clear, go back and reread the last two paragraphs until it is.
Lines 23 and 24 will cause the procedure named Write_A_Message to be called 8 times, each time writing a line of output to the monitor. Suffice it to say at this time, that the value of the variable Count, as defined here, is available globally, meaning anywhere in the entire Pascal program. We will define the scope of variables shortly. Finally, the last procedure call is made, causing the ending message to be displayed, and the program execution is complete.
THE UNBROKEN RULE OF PASCAL
Having examined your first Pascal procedures, there is a fine point that is obvious but could be easily overlooked. We mentioned the unbroken rule of Pascal in an earlier chapter and it must be followed here too. "Nothing can be used in Pascal until it has been defined". The procedures must all be defined ahead of any calls to them, once again emphasizing the fact that they are part of the Declaration Part of the program, not the Statement Part.
Compile and run PROCED1.PAS to verify that it does what you expect it to do.
MORE PROCEDURE CALLS
Example program -----> PROCED2.PAS
Assuming you have run PROCED1.PAS successfully and understand its output, let's go on to PROCED2.PAS and examine it. In this program we will see how to call a procedure and take along some data for use within the procedure. To begin with, notice that there are three procedure calls in the Statement Part of the program and each has an additional term not contained in the calls in the last program, namely the variable name Index within brackets. This is Pascal's way of taking along a variable parameter to the procedure.
Let's begin with line 22 to study how we pass a variable to a procedure. You will notice that the variable Index is defined as an integer type variable in the very top of the Declaration Part. Since we are taking an integer type variable along when we visit the procedure Print_Data_Out, it had better be expecting an integer variable as input or we will have a type mismatch. In fact, observing the procedure heading itself in line 7, indicates that it is indeed expecting an integer variable but it prefers to call the variable Puppy inside of the procedure. Calling it something different poses no problem as long as the main program doesn't try to call its variable Puppy, and the procedure doesn't try to use the name Index to refer to the data. Both are actually referring to the same piece of data but they simply wish to refer to it by different names.
FORMAL AND ACTUAL PARAMETERS
The parameters listed within the parentheses of the procedure header are called the formal parameters, whereas the parameters listed within the parentheses of the procedure call in the main program are referred to as the actual parameters. Observe that the next procedure is called with Index as the actual parameter and the procedure prefers to use the name Cat as the formal parameter name. In both cases, the procedures simply print out the parameter passed to it, and each then try to modify the value passed to it before passing it back. We will see that one will be successful and the other will not.
We are in a loop in which Count is incremented from 1 to 3 and Pascal does not allow us to modify the loop variable so we make a copy of the value in line 21 and call it Index. We can modify Index in the main program if we desire.
CALL BY VALUE
In line 7, the procedure heading does not contain the reserved word var in front of the formal parameter and therefore the parameter passing is only one way because of the way Pascal is defined. Without the reserved word var in front of the variable Puppy, the system makes a copy of Index, and passes the copy to the procedure which can do anything with it, using its new name, Puppy, but when control returns to the main program, the original value of Index is still there. The copy of Index named Puppy is modified in the procedure, but the original variable named Index remains unchanged. You can think of the passed parameter without the var as one way parameter passing. This is a "call by value" because only the value of the actual variable is passed to the procedure.
CALL BY REFERENCE
In line 13, the second procedure has the reserved word var in front of its desired name for the variable, namely Cat, so it can not only receive the variable, it can modify it, and return the modified value to the main program. A copy is not made, but the original variable named Index is actually passed to this procedure and the procedure can modify it, therefore communicating with the main program. The formal parameter name, Cat in the procedure, is actually another name for the actual variable named Index in the main program. A passed parameter with a var in front of it is therefore a two way situation. This is a "call by reference" since a reference to the original variable is passed to the procedure.
SOME NEW TERMINOLOGY
To restate some of the new terminology in the last few paragraphs, the parameter name in the calling program is referred to as the actual parameter, and the parameter name in the procedure is referred to as the formal parameter. In the last example then, the actual parameter is named Index and the formal parameter in the procedure is named Cat. It should be pointed out that it is called a formal parameter whether it is a "call by reference" or a "call by value". This terminology is used in many other programming languages, not only in Pascal.
When you run this program, you will find that the first procedure is unable to return the value of 12 back to the main program, but the second procedure does in fact succeed in returning its value of 35 to the main program. Spend as much time as you like studying this program until you fully understand it. It should be noted that as many parameters as desired can be passed to and from a procedure by simply making a list separated by commas in the calls, and separated by semicolons in the procedure. This will be illustrated in the next example program.
Compile and run PROCED2.PAS and study the output. You should be able to comprehend all of the output. If it is not clear, reread the last few paragraphs.
Example program ------> PROCED3.PAS
To add to your knowledge of Pascal, examine the program PROCED3.PAS for an example of a procedure call with more than one variable in the call. Normally, you would group the three input values together to make the program more readable, but for purposes of illustration, they are separated. Observe that the variable Fruit is a two way variable because it is the 3rd variable in the actual parameter list and corresponds to the 3rd formal parameter in the procedure header. Since the third variable is a "call by reference", it has the ability to return the sum of the other 3 variables to the main program. This is the reason it was defined this way.
Compile and run PROCED3.PAS to see that it does what you expect it to do based on the above explanation.
"CALL BY REFERENCE" OR "CALL BY VALUE"?
It may seem to you that it would be a good idea to simply put the word var in front of every formal parameter in every procedure header to gain maximum flexibility, but using all "call by references" could actually limit your flexibility. There are two reasons to use "call by value" variables when you can. The first is simply to shield some data from being corrupted by the procedure. This is becoming a very important topic in Software Engineering known as "information hiding" and is the primary basis behind Object Oriented Programming which will be discussed in chapters 14 and 15 of this tutorial.
Secondly is the ability to use a constant in the procedure call. Modify line 17 of PROCED3.PAS as follows;
and compile and run the program. Since Value1 is a "call by value", the constant 12 can be used and the program will compile and run. However, if you change line 17 to;
you will find that it will not compile because Total is a "call by reference" and the system must be able to return a value for the formal parameter Total. It cannot do this because 32 is a constant, not a variable. A call by reference must have a variable for the actual parameter. As a programming exercise, make Value1 a call by reference by adding the word var in front of it in line 6, and you will find that the compiler will not allow you to replace the variable Apple with the constant 12 as was suggested earlier in this section.
The prior discussion should indicate to you that both "call by value" and "call by reference" have a useful place in Pascal programming and it is up to you to decide which you should use.
When you are satisfied with the present illustration and you have compiled and executed PROCED3.PAS several times to study the results of the suggested changes, we will go on to study the scope of variables using PROCED4.PAS.
A MULTIPLY DEFINED VARIABLE
Example program ------> PROCED4.PAS
If you will examine PROCED4.PAS, you will notice that the variable Count is defined twice, once in the main program var block and once in the var block contained within the procedure named Print_Some_Data. This is perfectly legal and is within the Pascal definition.
The variable Index is defined only in the main program var block and is valid anywhere within the entire Pascal program, including the procedures and is said to be a global variable. The variable Count is also defined in the main program var block and is valid anywhere within the entire Pascal program, except within the procedure where another variable is defined with the same name Count. The two variables with the same name are in fact, two completely different variables, one being available only outside of the procedure and the other being available only within the procedure. The variable More_Stuff is defined within the procedure, so it is invisible to the main program, since it is defined at a lower level than that of the main program. It is only available for use within the procedure in which it is defined.
Any variable is available at any point in the program following its definition but only at the level of definition or below. This means that any procedure in the Declaration Part of a program can use any variable defined in the Declaration Part of the program provided that the definition occurs prior to the procedure. Any variable defined within a procedure cannot be used by the main program since the definition is at a lower level than the main program.
Be sure to compile and run PROCED4.PAS before continuing on to the next example program.
PROCEDURES CALLING OTHER PROCEDURES
Example program ------> PROCED5.PAS
Load and examine PROCED5.PAS to see an example of procedures that call other procedures. Keep in mind that, "Nothing can be used in Pascal until it has been defined", and the order of procedures will be clear in this example. Note that procedure Three calls procedure Two which in turn calls procedure One.
Compile and run PROCED5.PAS and study the output until you understand why it outputs each line in the order that it does.
Now that you have a good working knowledge of procedures, we need to make another important point. Remember that any Pascal program is made up of three parts, the Program Heading, the Declaration Part, and the Statement Part. The Declaration Part is composed of five unique components, four of which we will discuss in detail in the next chapter, and the last component, which is composed of some number of procedures and functions. We will cover functions in the next example, so for now simply accept the fact that it is like a procedure. A procedure is also composed of three parts, a Procedure Heading, a Declaration Part, and a Statement Part. A procedure, by definition, is therefore nothing more or less than another complete Pascal program embedded within the main program, and any number of procedures can be located in the Declaration Part of the main program. These procedures are all in a line, one right after another.
Since a procedure is defined like the main program, it would seem to be possible to embed another procedure within the Declaration Part of any procedure. This is perfectly valid and is often done, but remember that the embedded procedure can only be called by the procedure in which it is embedded, not by the main program. This is a form of information hiding which is becoming popular in modern software engineering.
The previous paragraph is probably a bit difficult to grasp. Don't worry about it too much now, as you become proficient as a Pascal programmer, you will very clearly see how embedded procedures are used.
NOW LET'S LOOK AT A FUNCTION
Example program ------> FUNCTION.PAS
Now to keep a promise, let's examine the program named FUNCTION.PAS to see what a function is and how to use it. In this very simple program, we have a function that simply multiplies the sum of two variables by 4 and returns the result. The major difference between a function and a procedure is that the function returns a single value and is called from within a mathematical expression, a Writeln command, or anywhere that it is valid to use a variable, since it is really a variable itself. Observing the Function Heading of the function, in line 6, you will notice that a function begins with the reserved word function. Further observation reveals the two input variables inside the parenthesis pair being defined as integer variables, and following the parenthesis is a colon and another integer. The last integer is used to define the type of the variable being returned to the main program.
Any call to this function is actually replaced by an integer value upon completion of the call. Therefore in line 14, the function is evaluated and the value returned is used in place of the function call. The value is returned by assigning the return value to the name of the function as illustrated in line 8. The result of the function is therefore assigned to the variable named Feet in line 14.
Note that a function always returns a value and it may return additional values if some of its formal parameters are defined as "call by reference". Be sure to compile and run this program.
NOW FOR THE MYSTERY OF RECURSION
Example program ------> RECURSON.PAS
One of the great mysteries of Pascal and several other popular programming languages, is the recursion of procedure calls. Simply defined, recursion is the ability of a procedure to call itself. Examine the Pascal example file RECURSON.PAS for an example of recursion. The main program is very simple, it sets the variable named Count to the value 7 and calls the procedure Print_And_Decrement. The procedure prefers to refer to the variable by the name Index but that poses no problem for us because we understand that the name of the formal parameter can be any legal identifier. The procedure writes a line to the video display with the value of Index written within the line, and decrements the variable.
The if statement introduces the interesting part of this program. If the variable is greater than zero, and it is now 6, then the procedure Print_And_Decrement is called once again. This might seem to create a problem except for the fact that this is perfectly legal in Pascal. Upon entering the procedure the second time, the value of Index is printed as 6, and it is once again decremented. Since it is now 5, the same procedure will be called again, and it will continue until the value of Index is reduced to zero when each procedure call will be completed one at a time and control will return to the main program.
ABOUT RECURSIVE PROCEDURES
This is really a stupid way to implement this particular program, but it is the simplest recursive program that can be written and therefore the easiest to understand. You will have occasional use for recursive procedures, so don't be afraid to try them. Remember that the recursive procedure must have some variable converging to something, or you will have an infinite loop. Compile and run this program and observe the value decrementing as the recursion takes place.
THE FORWARD REFERENCE
Example program ------> FORWARD.PAS
Occasionally you will have a need to refer to a procedure before you can define it. In that case you will need a forward reference. The example program named FORWARD.PAS has an example of a forward reference in it. In this program, each one of the procedures calls the other, a form of recursion. This program, like the last, is a very stupid way to count from 7 to 0, but it is the simplest program possible with the forward reference.
The first procedure, Write_A_Line, has its header defined in exactly the same manner as any other procedure but instead of the normal procedure body, only the reserved word forward is given in line 6. This tells the compiler that the procedure will be defined later. The next procedure is defined as usual, then the body of Write_A_Line is given with only the reserved word procedure and the procedure name. The variable reference has been defined earlier. In this way, each of the procedure names are defined before they are called.
It would be possible, by using the forward reference in great numbers, to move the main program ahead of all procedure definitions and have the program structured like some other languages. This style of programming would be perfectly legal as far as the compiler is concerned, but the resulting program would be very nonstandard and confusing. You would do well to stick with conventional Pascal formatting techniques and use the forward reference sparingly. Be sure you compile and run this program.
THE PROCEDURE TYPE
Example program ------> PROCTYPE.PAS
Examine the program named PROCTYPE.PAS. This is a new extension to the Pascal language by Borland beginning with version 5.0. In this program, the procedure Do_Math is defined as a procedure type in line 12, and three regular procedures are defined each of which have the same structure of formal parameters. In the program, since Do_Math is a procedure type that is compatible with each of the defined procedures, it can be assigned one of the other procedures, and a call to Do_Math is identical to a call to that procedure to which it is currently assigned. The program should be self explanatory with those few comments so you will be left to study the details on your own. It is important that you recognize that the procedure type variable is used to call several different procedures.
We have not yet studied the type yet, but we will in the next chapter.
Note the comments in lines 4 and 5 of the program. When using a procedure type or a function type, which is the topic of the next example program, TURBO Pascal requires that you use the compiler directive F+, which forces the system to use far calls for all procedure calls. Study the documentation for your version of TURBO Pascal to obtain more information on compiler directives.
Example program ------> FUNCTYPE.PAS
Examine the program named FUNCTYPE.PAS for an example of a program using some of the same techniques as the last program but instead uses a function type for the subprogram variable. This program should be simple for you to study on your own concerning the details of operation.
The only rule concerning the procedure and function types which must be stated, is that a subprogram type variable can only be assigned subprogram names if the list of actual parameters are identical for the type and the subprogram. This includes the type of the return value for a function. You should know that this can be done, because someday you will find a piece of Pascal code with this construct used. Of course, you will someday find a good use for it yourself.
Advance to Chapter 6
Return to the Table of Contents