
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.
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:
else above, and when A is not larger, the function hands back whatever rubbish was lying around - 67, say.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;
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.
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.
{$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
{$A-} line. Which of the three answers changes, and which do not?Writeln(Larger(3, 9)); to just Larger(3, 9);. What does Turbo say?{$A-} back, and in Larger delete else Larger := B (leave the ;). What is Larger(3, 9) now?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.
| Symptom | Cause |
|---|---|
| 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 function | A function used as a statement, with nowhere for its answer to go. |
| A function returns a strange value sometimes | Some way through it does not assign to the function's name. |
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.
S17, Your Own Types - naming your own kinds of value: Wall, Floor, Crate.