ZetCode

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.

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

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

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

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

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

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

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

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

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

The Algol 68 Genie project

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

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.