ZetCode

Algol 68 flexible rows

last modified November 13, 2026

A row declared with fixed bounds keeps those bounds for its whole life. A flexible row is a row variable whose bounds are part of its value rather than its mode, so an assignment may give it a row of a different length. This article describes the FLEX declaration and the operations that grow, shrink, and empty such a row.

Rows with changeable bounds

FLEX is written before the brackets of a row mode. The declaration still needs a set of bounds, which say how long the row is before the program assigns a value to it. The common starting point is an empty row with bounds 1 and 0.

basic.a68
BEGIN
  FLEX [1:0] INT row;
  print((whole(LWB row, 0), " ", whole(UPB row, 0), newline));
  row := (1, 2, 3);
  print((whole(LWB row, 0), " ", whole(UPB row, 0), newline));
  row := (7, 8);
  print((whole(UPB row, 0), newline))
END

The first line reports the empty bounds. The assignment of a three-element denotation changes the bounds to 1 and 3, and the next assignment shrinks the row to two elements. The identity declaration with = would have fixed the length, which is why the variable is declared with no initial value at all.

$ a68g basic.a68
1 0
1 3
2

Appending to a row

A flexible row does not grow by itself when an element is added, because the language has no operator for joining two integer rows. The operation is written as a procedure that allocates a row one element longer, copies the old elements, and assigns the new row back.

append.a68
PROC append = (REF FLEX []INT row, INT value) VOID:
  ( FLEX [1:UPB row + 1] INT wider;
    IF UPB row > 0 THEN wider[1:UPB row] := row FI;
    wider[UPB wider] := value;
    row := wider );

BEGIN
  FLEX [1:0] INT row;
  FOR i TO 4 DO
    append(row, i * i)
  OD;
  FOR i TO UPB row DO
    print((whole(row[i], 0), " "))
  OD;
  print((newline))
END

The parameter is a REF FLEX []INT, so the procedure can replace the caller's row. The local wider is one element longer than the old row, the copy fills the first elements, and the last one receives the new value. The IF copies the old elements when the row has any, and for the first call there is nothing to copy. The four calls produce the squares 1, 4, 9, and 16.

$ a68g append.a68
1 4 9 16

Shrinking and trimming

Assigning a slice to the same flexible row shortens it. The slice is evaluated first and copied into a new row, so the assignment is safe even though it reads and writes the same variable.

shrink.a68
BEGIN
  FLEX [1:5] INT row := (10, 20, 30, 40, 50);
  row := row[2:4];
  print((whole(LWB row, 0), " ", whole(UPB row, 0), " ", whole(row[1], 0), newline));
  row := row[1:0];
  print((whole(UPB row, 0), newline))
END

The slice keeps three values, and the assignment renumbers them from 1, so row[1] becomes 20 and the upper bound becomes 3. The empty slice row[1:0] then reduces the row to bounds 1 and 0, which is the empty row of the previous section. A row declared without FLEX rejects both assignments with a message about different bounds.

$ a68g shrink.a68
1 3 20
0

Empty rows and loops

An empty flexible row behaves like any other row with bounds 1 and 0. A loop that counts from LWB to UPB runs zero times, which is why the same code handles a row with and without elements.

loop.a68
BEGIN
  FLEX [1:0] INT row;
  FOR i TO UPB row DO
    print((whole(row[i], 0)))
  OD;
  print(("empty row skipped", newline))
END

The upper bound is 0, so the loop body never runs and only the message is printed. This is the reason a program can append in a loop without testing the length first, and the reason a loop over a row does not need a separate case for the empty one.

$ a68g loop.a68
empty row skipped

Flexible rows as parameters

A parameter of mode []INT accepts a flexible row as well as a fixed one, and it sees the current bounds. The parameter is a value, so the procedure may walk the row but cannot resize the caller's variable unless the parameter is declared with REF.

param.a68
PROC show = ([]INT row) VOID:
  ( FOR i FROM LWB row TO UPB row DO
      print((whole(row[i], 0), " "))
    OD;
    print((newline)) );

BEGIN
  FLEX [1:0] INT row;
  row := (1, 2, 3);
  show(row);
  row := (9);
  show(row)
END

The same procedure prints three values for the first call and one for the second, because it reads the bounds from its argument. The append procedure earlier needed REF precisely because it assigns a new row to the variable rather than only reading it.

$ a68g param.a68
1 2 3
9

Flexible rows of strings

FLEX may be applied to any row mode, and the append procedure generalises to rows of strings once the element mode is changed. The procedure then builds a list of names without knowing its final length.

strings.a68
PROC append = (REF FLEX []STRING row, STRING value) VOID:
  ( FLEX [1:UPB row + 1] STRING wider;
    IF UPB row > 0 THEN wider[1:UPB row] := row FI;
    wider[UPB wider] := value;
    row := wider );

BEGIN
  FLEX [1:0] STRING names;
  append(names, "Alice");
  append(names, "Bob");
  FOR i TO UPB names DO
    print((whole(i, 0), ": ", names[i], newline))
  OD
END

The body is identical to the integer version apart from the modes, which shows how orthogonal the row concept is. A STRING is itself a flexible row of characters, so the element mode of this row is flexible as well. Strings also support +:= directly, which is why appending to a string needs no procedure of its own.

$ a68g strings.a68
1: Alice
2: Bob

Next steps

The rows article describes fixed rows and multidimensional rows, and strings shows the same operations on rows of characters. The procedures article explains the REF parameters used by the append procedure, and loops covers the clauses that walk a row.

Source

Revised Report on the Algorithmic Language Algol 68

The Algol 68 Genie project

In this article we have declared flexible rows, changed their length by assignment, appended elements with a procedure, trimmed a row down to an empty one, walked a row whose bounds can be zero, passed flexible rows to procedures, and built a flexible row of strings. The rows article continues with fixed rows, and strings describes the flexible row of characters.

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.