Control Flow in ALGOL 68
Learn how to use conditionals, loops, and case expressions in ALGOL 68 with practical Docker-ready examples
Introduction
Control flow is what turns a list of instructions into a real program: deciding which branch to take, repeating work over a range of values, and choosing between alternatives. ALGOL 68 was designed with orthogonality in mind, so its control structures fit together in remarkably uniform ways. Every conditional, every loop, and every case clause follows the same basic rhythm — a keyword opens the construct, and a matching keyword (or its reverse) closes it.
Unlike ALGOL 60 and many modern languages, ALGOL 68 treats conditionals and case clauses as expressions that yield values, not just statements. An IF can appear on the right of an assignment, and a CASE can sit inside a print call. The language also offers a brief notation — (...|...|...) — that is exactly equivalent to the long form. This dual personality is part of what makes ALGOL 68 so expressive once you internalise it.
In this tutorial you will learn how ALGOL 68 expresses if/else decisions, case/conformity clauses, the universal FOR/WHILE/DO loop, and how to exit loops cleanly. All examples run on Algol 68 Genie inside Docker.
Conditional Expressions: IF, ELIF, FI
The most fundamental control construct in ALGOL 68 is the conditional clause. It uses IF, THEN, ELSE, ELIF, and FI (the reverse of IF). The brief form uses (, |, |:, and ) and is fully interchangeable with the long form.
Create a file named conditionals.a68:
BEGIN
INT score = 75;
IF score >= 90 THEN
print(("Grade: A", new line))
ELIF score >= 80 THEN
print(("Grade: B", new line))
ELIF score >= 70 THEN
print(("Grade: C", new line))
ELIF score >= 60 THEN
print(("Grade: D", new line))
ELSE
print(("Grade: F", new line))
FI;
# IF is an expression — it yields a value #
STRING status = IF score >= 60 THEN "pass" ELSE "fail" FI;
print(("Status: ", status, new line));
# The brief form is equivalent #
INT n = 42;
print(("n is ", (n MOD 2 = 0 | "even" | "odd"), new line))
END
A few things to notice:
- Comments are delimited by
#on both sides (or with the keywordCO). FIcloses everyIF, even one with severalELIFbranches — there is noEND IF.- The conditional yields a value of whatever common mode the branches share (
STRINGin the example).
Case Clauses: CASE, IN, OUT, ESAC
When you need to dispatch on an integer (or string, in extended form), CASE is more idiomatic than a chain of ELIFs. Like IF, CASE is an expression and has a brief form (...|,...|...).
Create a file named case_clause.a68:
BEGIN
# Integer CASE — the value selects the 1-based branch #
FOR day FROM 1 TO 7 DO
STRING name =
CASE day IN
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
OUT
"unknown"
ESAC;
print((name, new line))
OD;
# Brief form is identical in meaning #
INT month = 4;
print(("Quarter ", (month | 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 | 0), new line))
END
ALGOL 68 case selectors are 1-based: CASE 1 IN a, b, c ESAC returns a. If the index falls outside the range, the OUT branch (the brief-form trailing value) is used. This makes CASE safe by construction — there is no fall-through, and the language forces you to handle out-of-range values.
Loops: The Universal FOR/WHILE/DO
ALGOL 68 has a single, beautifully general loop construct. Every loop is a particular shape of the same template:
FOR var FROM start BY step TO end WHILE condition DO body OD
Any clause may be omitted. Drop the FOR part and you have a WHILE loop. Drop the WHILE part and you have a counted FOR. Drop everything except DO ... OD and you have an infinite loop.
Create a file named control_flow.a68:
BEGIN
# Counted FOR loop — print squares from 1 to 5 #
print(("Squares:", new line));
FOR i FROM 1 TO 5 DO
print((" ", i, " squared = ", i * i, new line))
OD;
# FOR with a step — count down by 2 #
print(("Countdown:", new line));
FOR i FROM 10 BY -2 TO 0 DO
print((" ", i, new line))
OD;
# Pure WHILE loop — collect digits of a number #
INT n := 12345;
INT digits := 0;
WHILE n > 0 DO
digits := digits + 1;
n := n OVER 10
OD;
print(("12345 has ", digits, " digits", new line));
# Combined FOR/WHILE — stop early when a condition fails #
print(("Powers of 2 below 100:", new line));
FOR k FROM 0 WHILE 2 ** k < 100 DO
print((" 2^", k, " = ", 2 ** k, new line))
OD
END
Two operators worth knowing here: OVER is integer (truncating) division, and ** is the power operator. Note also the distinction between identity declarations (INT x = 12345; — a constant binding using =) and variable declarations (INT n := 12345; — a mutable variable using :=). The loop counter i in a FOR clause is itself a constant within each iteration; you cannot assign to it.
Exiting Loops Early: GOTO and Labels
ALGOL 68 has no break or continue keyword. Instead, when you need to leave a loop early, you use a labelled GOTO. This sounds primitive, but in practice it is rare — most loops are best written with a WHILE condition that captures the exit logic directly.
Create a file named early_exit.a68:
BEGIN
# Search for the first multiple of 7 between 20 and 50 #
INT found := -1;
FOR i FROM 20 TO 50 DO
IF i MOD 7 = 0 THEN
found := i;
GOTO done
FI
OD;
done:
IF found > 0 THEN
print(("First multiple of 7 in [20,50]: ", found, new line))
ELSE
print(("None found", new line))
FI;
# The idiomatic alternative: use WHILE to express the exit condition #
INT j := 20;
WHILE j <= 50 AND j MOD 7 /= 0 DO
j := j + 1
OD;
print(("Same answer via WHILE: ", j, new line))
END
The /= operator means “not equal” — ALGOL 68 also accepts NE. Labels are written as identifiers followed by a colon and may appear anywhere a statement may appear.
Running with Docker
| |
Expected Output
Output from conditionals.a68:
Grade: C
Status: pass
n is even
Output from case_clause.a68:
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Quarter +2
Output from control_flow.a68:
Squares:
+1 squared = +1
+2 squared = +4
+3 squared = +9
+4 squared = +16
+5 squared = +25
Countdown:
+10
+8
+6
+4
+2
+0
12345 has +5 digits
Powers of 2 below 100:
2^ +0 = +1
2^ +1 = +2
2^ +2 = +4
2^ +3 = +8
2^ +4 = +16
2^ +5 = +32
2^ +6 = +64
Output from early_exit.a68:
First multiple of 7 in [20,50]: +21
Same answer via WHILE: +21
Note that Algol 68 Genie’s default print formatting for integers includes a leading sign and right-alignment within a width. This is part of the standard formatting and not a quirk of the program — printf with an explicit format string can be used for tighter output.
Key Concepts
IF ... THEN ... ELIF ... ELSE ... FIis the long form; the brief form(cond | yes | no)is exactly equivalent and often used for one-liners.- Conditionals are expressions — they yield a value of the common mode of their branches, so they can sit on the right of an assignment or inside another expression.
CASE ... IN ... OUT ... ESACdispatches on a 1-based integer index, with a mandatory out-of-range branch — there is no fall-through and nobreak.- One loop to rule them all:
FOR var FROM a BY b TO c WHILE cond DO ... ODis the universal loop; omitting clauses yields counted loops, while loops, and infinite loops. - Identity vs variable:
INT x = 5;binds a constant with=, whileINT x := 5;declares a mutable variable assigned with:=. Loop counters are constants within each iteration. - Early exit uses labelled
GOTO— there is nobreakorcontinue. Most loops can express their exit condition in theWHILEclause instead. - Closing keywords are reversed openers:
IF/FI,CASE/ESAC,DO/OD. This visual symmetry is a hallmark of ALGOL 68’s design. - Operators worth remembering:
MOD(remainder),OVER(integer division),**(power),/=orNE(not equal),AND/OR/NOT(boolean logic).
Running Today
All examples can be run using Docker:
docker pull codearchaeology/algol68:latest
Comments
Loading comments...
Leave a Comment