Turbo Pascal 2.0 course cover
← Back to Courses
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.