What are functions and procedures?

Description

Pascal encourages modular programming, where a program is created from a number of smaller and simpler pieces known as modules. Modules can make call other modules (i.e. execute other modules), or even call themselves. Pascal supports two kinds of modules, which are called functions and procedures.

Functions are called in expressions, and each function call has a value in an expression. Procedures on the other hand are called in procedure statements. In all other respects functions and procedures are identical, and the generic term subroutine will be used to refer to both types of modules.

Sometimes it is useful to create subroutines that accept input data and/or produce output data. One way to achieve this to have the subroutines use global variables (i.e. variables declared in the main program block) to store the input and output data. However the overuse of global variables can make programs difficult to understand and change. The basic problem is that since gloval variables are not specific to any particular subroutine, it can be difficult to keep track of which subroutines use which global variables and when. As a result, subroutines can become tightly intertwined making it very difficult to change one subroutine without changing the others.

Another way to create subroutines that accept input data and/or generate output data is to give each subroutine its own set of special variables to accept input data and store output data. These special variables are called parameters. When a subroutine is declared a possibly empty list of parameters (called formal parameters) is specified, and within the subroutine the formal parameters are referenced to accept input data and store output data. When a subroutine is called the caller must supply the actual data (called actual parameters) for each formal parameter specified by the subroutine declaration.

Pascal supports four kinds of formal parameters (value parameters, variable parameters, function parameters, and procedure parameters).

Value parameters are passed by value (i.e. when subroutines with value parameters are called, the corresponding actual parameters are expressions, and the values of these expressions become the initial values of the value parameters. Subroutines reference value parameters just like normal variables, and can retrieve and change the value stored in them, however changes made to the value stored in value parameters are invisible to the caller.

Variable parameters are passed by reference (i.e. when subroutines with variable parameters are called, the corresponding actual parameters are variables, and the addresses of these variables are passed into the variable parameters). Subroutines reference variable parameters just like normal variables, however references to variable parameters actually reference the variables passed as the corresponding actual parameters.

Function parameters are passed by reference (i.e. when subroutines with function parameters are called, the corresponding actual parameters are functions, and the addresses of these functions are passed into the function parameters. Subroutines can call function parameters just like normal functions, however calling function parameters actually calls the functions passed as the corresponding actual parameters.

Procedure parameters are passed by reference (i.e. when subroutines with procedure parameters are called, the corresponding actual parameters are procedure, and the addresses of these procedure are passed into the procedure parameters. Subroutines can call procedure parameters just like normal procedure, however calling procedure parameters actually calls the procedure passed as the corresponding actual parameters.

Example

For example here is an example of a simple program with a procedure.

   program simple(output);

      procedure say (message : string);
      begin
         writeln(message)
      end;

   begin
      say('Hello world');
      say('Good bye!');
   end.

The program contains a procedure called say which takes a single value parameter. When the procedure is called for the first time the actual parameter is the expression 'Hello world', which is passed into the formal parameter message. So the initial value of message is 'Hello world'. The call to the built-in procedure writeln causes the value of message (i.e. 'Hello world') to be written to the standard output stream. When the procedure is called for the second time the actual parameter is the expression 'Good bye!', which is passed into the formal parameter message. So the initial value of message is 'Good bye!'. The call to the built-in procedure writeln causes the value of message (i.e. 'Good bye!') to be written to the standard output stream.

Pascal supports recursive function and procedure calls (i.e. Pascal allows functions and procedures to call themselves either directly or indirectly). For example a procedure A can call itself directly or it can call a procedure B which in turn calls procedure A.

Functions and procedures must be declared before they can be called. This creates a problem when you have functions or procedures that call each other. For example suppose you have the program below.

   program test(output);

      procedure a(x : integer);
      begin
        writeln(x);
        b(x+1)
      end;

      procedure b(x : integer);
      begin
        writeln(x);
        a(x+1)
      end;

   begin
      a(1);
   end.

If you try to compile this program, the compiler will complain about the call b(x+1) that occurs in procedure a because this call occurs before procedure b is declared. You can try to correct this problem by moving the declaration of procedure b before the declaration of procedure a like so

   program test(output);

      procedure b(x : integer);
      begin
        writeln(x);
        a(x+1)
      end;

      procedure a(x : integer);
      begin
        writeln(x);
        b(x+1)
      end;

   begin
      a(1);
   end.

but if you try to compile this program, the the compiler will now complain about the call to a(x+1) that occurs in procedure b, because this call now occurs before procedure a is declared.

The solution to this problem is to use the forward directive as illustrated by the program below:

program test(output);

   procedure b(x : integer); forward;

   procedure a(x : integer);
   begin
      writeln(x);
      b(x+1)
   end;

   procedure b;
   begin
      writeln(x);
      a(x+1)
   end;

begin
   a(1);
end.

See the forward directive for more information.

As an extension to Standard Pascal, Irie Pascal supports calling functions and procedures inside Windows DLLs using the external directive.

See the external directive for more information.

Syntax

The syntax for function and procedure declarations is given below:

(NOTE: for clarity some parts of the syntax are omitted, see Irie Pascal Grammar for the full syntax):

   function-declaration =
       function-heading ';' directive |
       function-identification ';' function-block |
       function-heading ';' function-block

   procedure-declaration =
       procedure-heading ';' directive |
       procedure-identification ';' procedure-block |
       procedure-heading ';' procedure-block

   block = declarative-part statement-part

   compound-statement = 'begin' statement-sequence 'end'

   declaration-group =
             label-declaration-group |
             constant-definition-group |
             type-definition-group |
             variable-declaration-group |
             function-declaration  | 
             procedure-declaration

   declarative-part = { declaration-group }

   directive = forward-directive | external-directive

   formal-parameter-list = '(' formal-parameter-section { ';' formal-parameter-section } ')'

   formal-parameter-section = value-parameter-specification |
                  variable-parameter-specification |
                  procedure-parameter-specification |
                  function-parameter-specification

   function-block = block

   function-heading = 'function' identifier [ formal-parameter-list ] ':' result-type

   function-identification = 'function' function-identifier

   function-identifier = identifier

   function-parameter-specification = function-heading

   identifier = letter { letter | digit }

   identifier-list = identifier { ',' identifier }

   procedure-block = block

   procedure-heading = 'procedure' identifier [ formal-parameter-list ]

   procedure-identification = 'procedure' procedure-identifier

   procedure-identifier = identifier

   procedure-parameter-specification = procedure-heading

   result-type = type-identifier

   statement-part = compound-statement

   statement-sequence = statement { ';' statement }

   type-identifier = identifier

   value-parameter-specification = identifier-list ':' type-identifier

   variable-parameter-specification = 'var' identifier-list ':' type-identifier