
Programs grow. The guessing game in S14 was fifteen lines; Warehouse will be hundreds. The way to keep a big program readable is to break it into pieces, give each piece a name that says what it does, and then write the program in terms of the names. Pascal calls those pieces procedures, and you have been using Turbo's own - Writeln, Readln, Delete - since S4. Now you write your own.
program Lines;
procedure Line;
begin
Writeln('----------');
end;
begin
Line;
Writeln('Hello');
Line;
end.
The procedure is declared after the program line (and after any var), before the program's own begin. It looks like a small program: the word procedure, a name, a semicolon, and a begin ... end - with a semicolon after its end, not a full stop. Then the name on its own is a new statement: Line; does whatever the procedure says.
A procedure must be declared before anything uses it. Turbo reads the program from the top, and a name it has not yet met is Error 41: Unknown identifier - the same as a misspelling.
A procedure becomes far more useful when it can be told things:
procedure Row(N: Integer; C: Char);
var
I: Integer;
begin
for I := 1 to N do Write(C);
end;
N and C are parameters. Row(10, '#') runs the procedure with N as 10 and C as '#', and prints ten #s. The values given in the call - the arguments - are matched to the parameters in order, and must be the right kinds: Row('#', 10) is Error 44: Type mismatch, and Row(10) with one missing is Error 3: ',' expected. An argument can be any expression: Row(W - 2, ' ').
Row declares its own I, under its own var. That I belongs to Row alone: it exists while Row runs, and the rest of the program cannot see it (Error 41 if it tries). If the program has a variable called I too, they are two different variables that happen to share a name; inside Row, I means Row's own.
A procedure can use the program's variables - those declared at the top - but a procedure that works only through its parameters and its own variables is one you can move to another program and trust. That is the habit to form.
Normally a parameter is a copy of the argument. A procedure can change its copy as much as it likes and the caller's variable is untouched. To let a procedure change the caller's variable itself, put var in front of the parameter:
procedure Swap(var P, Q: Integer);
var
T: Integer;
begin
T := P;
P := Q;
Q := T;
end;
Swap(A, B) really swaps A and B. Without the var, it would swap two copies and leave A and B as they were. A var parameter must be given a variable - Swap(A, 5) makes no sense, and Turbo says Error 41.
A parameter's type must be a name. procedure Greet(Who: string[20]) is refused (Error 36: Type identifier expected). Give the string type a name first, in a type section before var:
type
Str20 = string[20];
and then use it: procedure Greet(Who: Str20). A Str20 variable, or text in quotes, can then be passed to Who. A var parameter is stricter: it must be given a variable of exactly that type - a string[10] passed to a var parameter of type Str20 is Error 44. Declaring all your strings with the same named type avoids the problem.
program Boxes;
procedure Row(N: Integer; C: Char);
var
I: Integer;
begin
for I := 1 to N do Write(C);
end;
procedure Box(W, H: Integer);
var
I: Integer;
begin
Row(W, '#');
Writeln;
for I := 1 to H - 2 do
begin
Write('#');
Row(W - 2, ' ');
Writeln('#');
end;
Row(W, '#');
Writeln;
end;
begin
Box(10, 4);
Box(4, 3);
end.
Box uses Row, so Row comes first. The program itself is two lines, and they say exactly what they do.
Starting from
Turbo freshly started, Y, a new work file called BOXES.
What you should see
##########
# #
# #
##########
####
# #
####
Box(10, 4) to Box(20, 2). Why is there nothing between the top and the bottom?procedure Row to below procedure Box. What does Turbo say, and where?Box, change the first Row(W, '#') to Row('#', W). What does Turbo say?15.1 Write a procedure Greet that takes a name and prints Hello, and the name. Call it three times with different names.
15.2 Write a procedure Order(var A, B: Integer) that swaps A and B if A is larger, so that afterwards they are in order. Try it with 9 and 4, and with 2 and 5.
15.3 Using Row, write a procedure Triangle(H) that draws a triangle of #s H rows high.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
Error 41 at a call of your procedure | It is declared further down, or its name is misspelt. Declare it above the code that calls it. |
Error 36: Type identifier expected in a heading | A type written out, such as string[20], in a parameter list. Name it under type and use the name. |
Error 44: Type mismatch at a call | The arguments are in the wrong order or of the wrong kind - or a string of another length given to a var string parameter. |
Error 3: ',' expected at a call | Too few arguments. |
Error 41 on a var argument | A value, not a variable, given to a var parameter. |
| A procedure's changes vanish | Its parameter is not var, so it changed a copy. |
procedure Name(parameters); followed by its own var and begin ... end; makes a new statement, Name(arguments). Declare procedures before their use. Parameters are copies unless marked var, which lets the procedure change the caller's variables. A procedure's own variables are its alone. Parameter types must be names - declare them under type.
S16, Functions, And One That Calls Itself - procedures that hand back a value, and a procedure that uses itself.