Algol 68 program structure
last modified November 13, 2026
An Algol 68 program is a unit, and every unit yields a value. Clauses combine smaller units into larger ones: a serial clause sequences them, a collateral clause groups them, and a closed clause encloses declarations together with a unit. This article describes those forms and the scope rules that go with them.
Units and clauses
A unit is the smallest piece of a program that can be elaborated, such as a
literal, a name, a formula, or a procedure call. A clause is a unit built
from other units. The value of a serial or closed clause is the value of its
last unit, which is why a declaration can be initialised with a whole
BEGIN ... END block.
Algol 68 does not separate statements from expressions in the way C or Java do. An assignment is a unit with a value, a procedure call is a unit, and a closed clause is a unit. Where a value is not needed, the unit is used in a void context and its value is discarded.
Closed clauses
A closed clause starts with BEGIN, contains declarations and
units separated by semicolons, and ends with END. Its value is
the value of the last unit, so it can be used on the right-hand side of a
declaration.
BEGIN
INT result = (BEGIN
INT a := 2, b := 3;
a * b
END);
print((whole(result, 0), newline))
END
The inner closed clause declares two variables, multiplies them, and yields
the product. The outer declaration binds result to that value.
The parentheses around the inner clause are needed because the clause appears
inside a declaration.
$ a68g closed.a68 6
Serial clauses
A serial clause contains units separated by semicolons and enclosed in parentheses. It performs each unit in turn and yields the value of the last one. A serial clause is useful when a single unit is expected but several steps are needed.
BEGIN
(print(("first "));
print(("second", newline)));
print(("after the serial clause", newline))
END
The parenthesised group prints first and second in
order. The semicolon after the closing parenthesis separates the group from
the following print. Unlike a collateral clause, a serial clause
guarantees the order of its units.
$ a68g serial.a68 first second after the serial clause
Collateral clauses
A collateral clause contains units separated by commas and enclosed in parentheses. Its units are elaborated independently, and the clause yields a row of their values. The language does not require a particular order, so a collateral clause should not depend on side effects from its units.
BEGIN
(print(("left ")), print(("right", newline)))
END
This implementation prints left right, but the order is an
implementation detail. Use a serial clause when the order matters, and use a
collateral clause when the units are independent values.
$ a68g collateral.a68 left right
Conditional clauses
The compact conditional clause has the form
(condition | then-unit | else-unit). The condition must be a
BOOL; the clause yields the value of the chosen branch. It is a
unit, so it can appear wherever a value is expected.
BEGIN INT n := 7; print(((ODD n | "odd" | "even"), newline)); print(((n > 0 | "positive" | "non-positive"), newline)) END
Each conditional clause produces a string, which print then
writes. The full IF ... THEN ... ELIF ... ELSE ... FI form is
more readable when the branches contain several statements, while the
parenthesised form is convenient for choosing between two values.
$ a68g conditional.a68 odd positive
Case clauses
A case clause selects one of several units according to an integer. The units
follow IN, are separated by commas, and are closed by
ESAC. An optional OUT part handles values outside
the listed choices.
BEGIN
FOR i TO 3 DO
CASE i IN
print(("one", newline)),
print(("two", newline))
OUT
print(("many", newline))
ESAC
OD
END
The loop runs three times. The values 1 and 2 select the two listed units,
and the value 3 falls through to OUT. The units in a case clause
are separated by commas, because the clause chooses one of them rather than
performing all of them.
$ a68g case.a68 one two many
Nested clauses and scope
A closed clause may contain another closed clause. A declaration inside the inner clause hides a declaration with the same name in the outer clause, and the inner name disappears when the inner clause ends.
BEGIN
INT x := 1;
BEGIN
INT x := 2;
print(("inner ", whole(x, 0), newline))
END;
print(("outer ", whole(x, 0), newline))
END
The inner x is a different variable from the outer one. The
inner clause prints 2, and after it ends the outer x is visible
again and still holds 1. This lexical scoping is the same idea found in
block-structured languages such as Pascal and Rust.
$ a68g scope.a68 inner 2 outer 1
Labels and GO TO
A unit may carry a label, and GO TO transfers control to it.
Algol 68 has no break statement, so a label is the direct way to
leave a loop early. The label is written before the unit it names, followed
by a colon.
BEGIN
FOR i TO 10 DO
IF i = 4 THEN GO TO finished FI;
print((whole(i, 0), " "))
OD;
finished: print(("stopped", newline))
END
The loop prints 1, 2, and 3. On the fourth pass GO TO finished
jumps out of the loop and continues after OD. Labels are useful
for early exits, but a loop that can be written with a WHILE
condition is usually clearer.
$ a68g label.a68 1 2 3 stopped
Next steps
The modes article describes the values that these clauses work with, and the variables article explains names, references, and storage. The basics article shows the same units in small complete programs.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have seen how units combine into closed, serial, collateral, conditional, and case clauses. Scope and labels complete the picture of control flow. The modes article continues with the values these clauses produce.
Author
List all Algol 68 tutorials.