Algol 68 coercions
last modified November 13, 2026
Algol 68 allows a value of one mode to be used where another mode is expected, provided the change loses no information and the surrounding context permits it. Such a change is a coercion, and it happens without any call or cast in the source. This article describes the coercions the language defines and the contexts in which each of them applies.
Contexts
The position of a unit decides which coercions are available. A declaration
and an argument of a procedure give a strong context, where the
required mode is known. The operands of an operator form a weak
context, and a condition after IF or WHILE forms a
meek context, in which only a boolean is accepted.
A coercion is applied only where the required mode is known, and only when it cannot lose information. A reference is dereferenced when its value is needed, and the value that comes out may then be widened. The sections below take the coercions one at a time.
Widening
Widening moves a value to a mode that can represent every value of the
original one: an INT becomes a REAL, a
REAL becomes a COMPL, and a mode becomes its
LONG variant. The reverse direction is never a coercion.
BEGIN REAL r = 1 + 2.5; LONG INT big = 7; print((fixed(r, 0, 1), newline)); print((whole(big, 0), newline)) END
In the first declaration the integer 1 is widened to a real, so the addition
happens in REAL and the result is 3.5. In the second, the
integer 7 is widened to LONG INT. Both conversions are accepted
because the wider mode can hold every value of the narrower one.
$ a68g widening.a68 3.5 7
Dereferencing
A reference designates a value stored elsewhere. When a reference appears where the designated mode is expected, the reference is dereferenced automatically, so no explicit operator is needed to read or to compute with the value behind it.
BEGIN INT x := 10; REF INT p = x; print((whole(p + 5, 0), newline)); p := 20; print((whole(x, 0), newline)) END
p + 5 reads the integer that p designates, so the
sum is 15. The assignment p := 20 stores 20 in the same cell, and
x then holds 20. Dereferencing is what makes a reference usable
without a special syntax for reading through it.
$ a68g deref.a68 15 20
Rowing
A collateral clause such as (1, 2.5, 3) produces several values.
In a strong context that expects a row, the values are collected into a row,
and each of them may be widened first. This is how row denotations are
written.
BEGIN []REAL row = (1, 2.5, 3); print((fixed(row[1], 0, 1), " ", fixed(row[2], 0, 1), " ", fixed(row[3], 0, 1), newline)); print((whole(UPB row, 0), newline)) END
The two integers in the denotation are widened to reals, so the whole row has
mode []REAL. Its bounds are inferred from the number of values,
which gives an upper bound of 3. A row declared with := cannot
infer its bounds and needs them written out, as in
[1:3] REAL row := (1, 2.5, 3).
$ a68g rowing.a68 1.0 2.5 3.0 3
Deprowing
Deprowing is the opposite of rowing: a row is reduced to one of its elements. It happens when a row name is subscripted with as many subscripts as the row has dimensions, so a two-dimensional row needs two subscripts and a one-dimensional row needs one.
BEGIN [,]INT m = ((1, 2), (3, 4)); []INT row = (10, 20, 30); print((whole(m[2, 1], 0), newline)); print((whole(row[2], 0), newline)) END
m[2, 1] selects the single element in the second row and the
first column, so both dimensions disappear and the result is an
INT. row[2] does the same for a one-dimensional
row and yields 20. A slice such as row[2:3] is a different
construct: it keeps the dimension and produces a new row.
$ a68g deprowing.a68 3 20
Uniting
A union mode holds a value of one of several modes. Assigning an
INT or a REAL to a name of union mode is a
coercion, and a case clause with a type inquiry recovers the original mode.
The same mechanism lets print accept values of many modes.
MODE VALUE = UNION (INT, REAL);
BEGIN
VALUE v = 7;
CASE v IN
(INT i): print(("int ", whole(i, 0), newline)),
(REAL r): print(("real ", fixed(r, 0, 1), newline))
ESAC;
VALUE w = 2.5;
CASE w IN
(INT i): print(("int ", whole(i, 0), newline)),
(REAL r): print(("real ", fixed(r, 0, 1), newline))
ESAC
END
The first value starts as an INT, and the case clause selects the
INT branch. The second is a real denotation, so the union holds a
REAL and the second branch runs. Had it been written as
2, the first branch would have run instead. The branch parameters
i and r have the modes named in the inquiry, so the
original value is available without a conversion.
$ a68g uniting.a68 int 7 real 2.5
Voiding
A value used where no value is needed is voided, which means it is discarded. This happens to the result of a procedure called for its effect, and to a formula that stands alone in a serial clause. The coercion is legal, but Genie warns when a formula's value is dropped.
PROC compute = INT: (print(("computing", newline)); 7);
BEGIN
compute;
print(("result discarded", newline))
END
compute returns an integer, but the call stands as a unit of its
own, so the result is voided after the procedure has printed its line. A
formula such as 4 + 1; is voided in the same way, and Genie adds
a warning that the value of the formula will be voided.
$ a68g voiding.a68 computing result discarded
Rejected coercions
The coercions above never lose information. Narrowing, on the other hand, is
rejected: INT n = 1.5; fails because a real cannot be coerced to
an integer, and REAL r = lr; fails after a
LONG REAL lr. The condition of an IF is a meek
context, so IF 1 THEN is refused as well, even though an integer
can be widened to a real.
The remedy is an explicit conversion: ENTIER or ROUND
turns a real into an integer, and a wider mode is kept where no loss is
acceptable. Keeping these conversions explicit is the point of the rule,
because each of them can lose information or change the result of a program.
Next steps
The operators article shows the contexts in which coercions occur, and the modes article describes the modes that take part in them. The variables article explains references and dereferencing from the storage side, and program structure covers the clauses in which the coercions apply.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have seen widening, dereferencing, rowing, deprowing, uniting, and voiding at work, and looked at the conversions the language refuses. The operators article provides the formulas in which most of these coercions take place.
Author
List all Algol 68 tutorials.