ZetCode

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.

widening.a68
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.

deref.a68
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.

rowing.a68
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.

deprowing.a68
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.

uniting.a68
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.

voiding.a68
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

The Algol 68 Genie project

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

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Algol 68 tutorials.