Algol 68 strings
last modified November 13, 2026
Algol 68 has no separate string type: a string is a row of characters, and
the name STRING abbreviates a flexible row of
CHAR. Everything that works on a row therefore works on a
string, and the operations specific to text are built from indexing, slicing,
and concatenation. This article describes those operations and the way
numbers become strings.
A row of characters
A string denotation is a sequence of characters in double quotes, and
STRING is the mode of that value. Because a string is a row, its
bounds are read with LWB and UPB, exactly as for a
row of numbers.
BEGIN STRING s = "Hello, Algol 68"; print((s, newline)); print((whole(LWB s, 0), " ", whole(UPB s, 0), newline)) END
The lower bound is always 1 and the upper bound is the number of characters, which is 15 here. The bounds are integers, so the same loops that walk through a row of numbers also walk through a string. An empty string has lower bound 1 and upper bound 0.
$ a68g chars.a68 Hello, Algol 68 1 15
Indexing
A subscript selects one character, and the result has mode CHAR.
A character denotation such as "l" compares equal to a character
read from the string, so a loop can count or locate letters.
BEGIN
STRING s = "Hello, Algol 68";
print((s[1], s[8:12], s[UPB s], newline));
FOR i TO UPB s DO
IF s[i] = "l" THEN print((whole(i, 0), " ")) FI
OD;
print((newline))
END
The first line prints the first character, a slice, and the last character,
which gives HAlgol8. The loop then reports every position that
holds a lower-case l, and the letters sit at positions 3, 4, 9,
and 12. Indexing is bounds checked at run time, so reading past
UPB raises an error instead of returning arbitrary memory.
$ a68g index.a68 HAlgol8 3 4 9 12
Slices and slice assignment
A slice written as s[from:to] yields a string of its own, and a
slice in the position of a variable may be assigned, which replaces the
characters in place. The replacement must have the same number of
characters.
BEGIN STRING s := "Hello, Algol 68"; s[1:5] := "Howdy"; print((s, newline)) END
The assignment replaces the five characters of Hello with
Howdy, so the string keeps its length and its punctuation. The
declaration uses :=, because the value of s is going
to change. A slice of a different length would be rejected rather than
resizing the string.
$ a68g modify.a68 Howdy, Algol 68
Concatenation
The operator + joins two strings and produces a new one. The
result has storage of its own, so no storage is shared with the operands and
the inputs remain unchanged.
BEGIN STRING first = "Algol", second = " ", third = "68"; STRING name = first + second + third; print((name, newline)); print((name + "!", newline)); print((whole(UPB name, 0), newline)) END
Three pieces are joined into Algol 68, and the same name is then
joined with an exclamation mark without changing the original. The upper
bound of the result is 8. Concatenation copies both operands, which makes it
safe to build a new string from a name and a slice of that same name.
$ a68g concat.a68 Algol 68 Algol 68! 8
Growing a string
STRING abbreviates FLEX []CHAR, a flexible row, so a
string variable may be resized. The operator +:= appends to it,
and assigning a slice shortens it.
BEGIN STRING s := "Algol"; s +:= " 68"; print((s, " ", whole(UPB s, 0), newline)); s := s[7:UPB s]; print((s, " ", whole(UPB s, 0), newline)) END
The append extends the string from five characters to eight, and the slice
s[7:8] then keeps the last two, which leaves 68.
Both operations adjust the bounds, because the variable is flexible.
Assigning the empty string "" would reduce it to bounds 1 and 0.
$ a68g flexible.a68 Algol 68 8 68 2
Comparison
Strings compare character by character, using the code of each character.
The operators are the same as for numbers: =, /=,
<, <=, >, and
>=. When one string is a prefix of the other, the shorter one
is smaller.
BEGIN
STRING a = "apple", b = "apply";
print((a = b, " ", a < b, " ", a > b, newline));
print(("abc" = "abc", newline));
print((a < "banana", newline))
END
The strings differ in their last character, e and y,
and e has the smaller code, so a < b is true.
The comparison is case sensitive, because upper-case and lower-case letters
have different codes. Two denotations with the same characters compare equal.
$ a68g compare.a68 F T F T T
Building a string in a loop
A common pattern starts with an empty string and appends one character per pass. Because the variable is flexible, the repeated append resizes it, and the loop below uses a downward step to reverse the text.
BEGIN
STRING s = "abcdef";
STRING r := "";
FOR i FROM UPB s BY -1 TO 1 DO
r := r + s[i]
OD;
print((r, newline))
END
The loop starts at the last character and counts down to the first, so
r collects f, e, d, and
so on. Joining a CHAR with a STRING widens the
character to a one-character string, which is why no explicit conversion is
needed. The result is the reversed text.
$ a68g reverse.a68 fedcba
Changing case
A character is an integer code in disguise, so ABS gives the code
and REPR turns a code back into a character. The difference
between an upper-case letter and its lower-case form is 32, which makes case
conversion a matter of arithmetic.
BEGIN
STRING s = "Algol 68";
STRING u := "";
FOR i TO UPB s DO
CHAR c = s[i];
IF c >= "a" AND c <= "z" THEN
u := u + REPR (ABS c - 32)
ELSE
u := u + c
FI
OD;
print((u, newline))
END
The test accepts only lower-case letters, so digits and spaces pass through
unchanged. Each accepted letter loses 32 from its code, which turns
l into L. The output keeps the space and the digits
of the original text.
$ a68g case.a68 ALGOL 68
Numbers as strings
whole converts an integer and fixed converts a real,
each taking a minimum field width as its second argument. A value narrower
than the field is padded on the left with spaces, which is how columns are
aligned without a separate formatting language.
BEGIN INT n = 255; REAL r = 3.14159; print((whole(n, 6), "|", newline)); print((fixed(r, 8, 2), "|", newline)) END
The integer needs four characters including its sign, so two spaces are added in a field of six. The real is printed with two decimals in a field of eight, which leaves three spaces. The vertical bar shows where the field ends. When a value does not fit its field, the procedures print asterisks instead of a truncated number.
$ a68g numbers.a68 +255| +3.14|
Next steps
The rows article generalises the operations of this article to rows of any mode, and the flexible rows article explains the resizing in more detail. The literals article describes string denotations, and procedures shows how to package the loops above into reusable units.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have treated a string as a row of characters, read and
assigned its slices, joined and grew strings, compared them, built one
character at a time, changed case with ABS and
REPR, and turned numbers into padded text. The
rows article continues with rows of other modes.
Author
List all Algol 68 tutorials.