Algol 68 procedures
last modified November 13, 2026
A procedure packages a unit under a name, gives it parameters, and optionally
returns a value. Algol 68 declares it with PROC, writes the modes
of the parameters in parentheses, writes the mode of the result after the
colon, and then gives the body. This article describes those declarations,
reference parameters, recursion, and the fact that a procedure is itself a
value that can be stored and passed.
Declaring a procedure
The simplest procedure returns nothing, so its result mode is
VOID. The body follows a colon and may be any unit, including a
single call of print. Calling the procedure writes its name,
and because there are no parameters, no parentheses follow.
PROC greet = VOID: print(("Hello from a procedure", newline));
BEGIN
greet;
greet
END
The declaration ends with a semicolon, like any other declaration, and the
body is the call of print after the colon. Each of the two calls
prints the line, so the output appears twice. A procedure that returns a
value behaves the same way, except that the value may be used in a formula.
$ a68g simple.a68 Hello from a procedure Hello from a procedure
Parameters and a result
Parameters are declared as a comma-separated list of modes and names, and the result mode is written between the closing parenthesis and the colon. The body must produce a value of that mode.
PROC area = (REAL width, REAL height) REAL: width * height; BEGIN print((fixed(area(3.0, 4.5), 0, 2), newline)); print((fixed(area(2.0, 2.0), 0, 2), newline)) END
The first call passes 3.0 and 4.5 and returns 13.5, the second returns 4.0.
The parameters are values, so the procedure receives copies and cannot change
the caller's variables through them. The arguments must have the declared
modes; an integer argument would be widened to REAL
automatically, but nothing else would be converted.
$ a68g params.a68 13.50 4.00
A body of several statements
When the body needs declarations or several statements, it is written as a parenthesised serial clause. The value of the last unit in that clause is the value of the procedure, so a conditional clause at the end chooses the result.
PROC classify = (INT n) STRING:
( IF n < 0 THEN "negative"
ELIF n = 0 THEN "zero"
ELSE "positive"
FI );
BEGIN
print((classify(-5), " ", classify(0), " ", classify(7), newline))
END
The parentheses around the body form a serial clause with a single unit, and
that unit is the conditional clause. Because every branch yields a string,
the clause has mode STRING and the declaration is accepted. The
calls print the three classifications in one line.
$ a68g body.a68 negative zero positive
Reference parameters
A parameter declared with REF designates a variable rather than
copying its value, so the procedure can store into the caller's variable.
The argument must be a name of the required mode, not an arbitrary formula.
PROC swap = (REF INT a, REF INT b) VOID: (INT t := a; a := b; b := t); BEGIN INT x := 1, y := 2; swap(x, y); print((whole(x, 0), " ", whole(y, 0), newline)) END
The body saves the first value in a local variable and then exchanges the two
cells. The call passes the names x and y, so the
assignments reach the caller's variables and the output is
2 1. Passing a formula such as swap(x, 1) would be
rejected, because a formula does not designate storage.
$ a68g swap.a68 2 1
Recursion
A procedure may call itself, and the declaration is visible inside its own body. Recursion is natural in Algol 68 because a procedure is an ordinary declaration, so the name is in scope from the start of the body.
PROC factorial = (INT n) INT:
IF n <= 1 THEN 1 ELSE n * factorial(n - 1) FI;
BEGIN
FOR i TO 6 DO
print((whole(factorial(i), 0), " "))
OD;
print((newline))
END
The base case returns 1 for 0 and 1, and every other call multiplies its argument by the factorial of the next smaller number. The loop prints the first six factorials. The recursive call appears inside a formula, which is allowed because the procedure yields an integer like any other operand.
$ a68g fact.a68 1 2 6 24 120 720
Procedures as values
A procedure has a mode of its own, written with PROC, the
parameter modes, and the result mode. A variable of that mode holds a
procedure, and assignment changes which one the name refers to.
PROC add = (INT a, INT b) INT: a + b; PROC mul = (INT a, INT b) INT: a * b; BEGIN PROC (INT, INT) INT op := add; print((whole(op(3, 4), 0), newline)); op := mul; print((whole(op(3, 4), 0), newline)) END
The variable op starts as add and later becomes
mul, so the same call text produces 7 and then 12. The mode
PROC (INT, INT) INT is part of the declaration, which means that
only procedures with two integer parameters and an integer result may be
assigned to it.
$ a68g procvar.a68 7 12
Procedures as arguments
Because a procedure is a value, it can be passed to another procedure. The parameter mode names the shape of the procedure that the argument must have, and the receiving procedure calls it like any other name.
PROC apply = (PROC (INT) INT f, INT x) INT: f(x); PROC square = (INT n) INT: n * n; PROC cube = (INT n) INT: n * n * n; BEGIN print((whole(apply(square, 5), 0), " ", whole(apply(cube, 5), 0), newline)) END
apply takes a procedure of mode PROC (INT) INT and
an integer, and calls the procedure with that integer. The two calls give 25
and 125. This is how a sorting routine can receive a comparison function,
which keeps the order of the elements separate from the algorithm that
rearranges them.
$ a68g higher.a68 25 125
Partial parametrisation
A call may leave some arguments out, writing an empty pair of parentheses in their place. The result is a new procedure with the remaining parameters, which Algol 68 calls partial parametrisation.
PROC add = (INT a, INT b) INT: a + b; BEGIN PROC (INT) INT inc = add(1,); print((whole(inc(41), 0), newline)) END
The declaration add(1,) supplies the first argument and leaves
the second one open, so inc has mode
PROC (INT) INT. Calling inc(41) completes the call
and returns 42. The omitted argument is marked by the comma alone, which is
why the empty parentheses are written after it.
$ a68g partial.a68 42
Scope in nested declarations
A procedure declared inside a clause sees the names that were declared before it. The binding is lexical: the body refers to the declaration that surrounds it, not to a variable of the same name in a clause that happens to be active at the time of the call.
BEGIN
INT base = 10;
PROC offset = (INT n) INT: n + base;
print((whole(offset(5), 0), newline));
BEGIN
INT base = 100;
print((whole(offset(5), 0), newline))
END
END
Both calls print 15, because offset was declared next to
base = 10 and keeps referring to that variable. The inner
base is a different variable with a shorter scope, and it does
not affect the procedure. This is the same rule that gives a procedure access
to the names of the clause in which it is written.
$ a68g nested.a68 15 15
Next steps
The loops article shows the clauses that these
procedures usually contain, and the
conditionals article explains the
branches used in the bodies above. The
modes article describes the parameter and result
modes, and variables and references
explains REF in more detail.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have declared procedures with and without results, passed values and references, written a recursive procedure, stored procedures in variables, passed them as arguments, left arguments open with partial parametrisation, and seen the lexical scope of a nested declaration. The strings article continues with the operations that procedures perform on text.
Author
List all Algol 68 tutorials.