Turbo Pascal 2.0 course cover
← Back to Modules
module
16

Functions, And One That Calls Itself

Introduction

Length(S) is not a statement: it gives back a number, which you use in a sum or a Writeln. That is a function. S15's procedures do things; a function works something out and hands back the answer. This section shows you how to write your own - and then something stranger and very powerful: a function, or procedure, that uses itself.

A Function

function Larger(A, B: Integer)
  : Integer;
begin
  if A > B then Larger := A
  else Larger := B;
end;

A function is declared like a procedure, with two differences. The heading ends with a colon and the type of the answer - here Integer. And somewhere inside, the answer is given by assigning to the function's own name: Larger := A. When the function finishes, the last value assigned to its name is the answer.

It is used like Turbo's own functions:

Writeln(Larger(3, 9));
Big := Larger(X, Y) * 2;

Two things to watch:

  • Every way through the function must assign the answer. Leave out the else above, and when A is not larger, the function hands back whatever rubbish was lying around - 67, say.
  • A function is not a statement. Larger(3, 9); on a line of its own, with nowhere for the answer to go, is Error 7: ':=' expected.

A function can hand back a string too, given a named type (S15):

function Shout(S: Str20): Str20;

Calling Itself

Here is a procedure that counts up to N:

procedure Count(N: Integer);
begin
  if N > 0 then
  begin
    Count(N - 1);
    Write(N, ' ');
  end;
end;

It does not use a loop. To count up to 5, it first counts up to 4 - by calling itself - and then writes 5. To count up to 4, it counts up to 3 and writes 4. And so on, down to counting up to 0, which does nothing. Then the writing happens on the way back: 1, 2, 3, 4, 5.

This is recursion. It sounds like a trick, and for counting it is one. But some problems are naturally recursive - "fill this square, then fill each empty square next to it" is one, and Warehouse will use exactly that to show which squares the worker can reach.

{$A-}

On this machine, recursion needs a compiler directive. Put this as the first line of any program that has a procedure or function calling itself:

{$A-}

Without it, Turbo compiles every procedure to keep one copy of its parameters and variables, shared by every call. That makes smaller code - a small program of three recursive routines comes to 315 bytes without {$A-} and 367 with it - and Borland's manual says faster code too. It is fine until a procedure calls itself - and then each call tramples the one before. Count(5) without {$A-} prints

0 0 0 0 0

because by the time the writing happens, the one shared N has been counted all the way down to 0. With {$A-}, each call keeps its own N, and the answer is 1 2 3 4 5.

The worst of it is that a recursive routine can come out right without {$A-} by luck - Power in this section's program does - so a missing {$A-} may pass every test you try and fail on the next. Make it a rule: recursion, {$A-}.

One more rule, even with {$A-}: do not pass a procedure's own local variable as a var parameter to a call of itself. That combination gives wrong answers regardless; Borland's manual warns of it, and it is true. Pass values, or use variables declared at the top of the program.

How deep can it go? A simple procedure calling itself three thousand times over worked without trouble.

The Code

{$A-}
program Funcs;

function Larger(A, B: Integer)
  : Integer;
begin
  if A > B then Larger := A
  else Larger := B;
end;

function Power(X, N: Integer): Integer;
begin
  if N = 0 then Power := 1
  else Power := X * Power(X, N - 1);
end;

procedure Count(N: Integer);
begin
  if N > 0 then
  begin
    Count(N - 1);
    Write(N, ' ');
  end;
end;

begin
  Writeln(Larger(3, 9));
  Writeln(Power(2, 10));
  Count(5);
  Writeln;
end.

Power(X, N) is X multiplied by itself N times: X to the power 0 is 1, and X to the power N is X times X to the power N - 1.

Starting from

Turbo freshly started, Y, a new work file called FUNCS.

What you should see

9
1024
1 2 3 4 5

Change One Thing

  • Delete the {$A-} line. Which of the three answers changes, and which do not?
  • Change Writeln(Larger(3, 9)); to just Larger(3, 9);. What does Turbo say?
  • Put {$A-} back, and in Larger delete else Larger := B (leave the ;). What is Larger(3, 9) now?

Exercises

16.1 Write a function Cube(N) and print the cubes of 3 and 10.

16.2 Write a function IsEven(N): Boolean, and use it to print the even numbers from 1 to 6.

16.3 Write a recursive function Sum(N): the sum of 1 to N is N plus the sum of 1 to N - 1, and the sum of nothing is 0. Print Sum(100).

Worked solutions are in Appendix II.

When It Goes Wrong

SymptomCause
A recursive routine gives zeros or nonsense, with no error{$A-} is missing from the first line.
Still wrong with {$A-}A local variable passed as a var parameter to the recursive call.
Error 7: ':=' expected at a functionA function used as a statement, with nowhere for its answer to go.
A function returns a strange value sometimesSome way through it does not assign to the function's name.

Summary

A function is declared with function Name(params): Type; and gives its answer by assigning to its own name; every way through must do so. Use it wherever a value can go, never as a statement. A procedure or function may call itself - recursion - and on this machine that needs {$A-} as the program's first line. Never pass a local as a var parameter to a recursive call.

Next

S17, Your Own Types - naming your own kinds of value: Wall, Floor, Crate.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.