ZetCode

Algol 68 error handling and assertions

last modified November 14, 2026

An Algol 68 program can fail in three places: the parser can reject the source before anything runs, a runtime check can stop the program in the middle of a statement, and a value read from the outside world can be of the wrong shape. The first is reported by --check, the second by the runtime and its exit status, and the third can be caught with a handler installed on a file.

This article shows the exit status of a normal run, a failed run, and a run that calls stop; it writes assertions that document the preconditions of a procedure, turns those assertions off for a release build, recovers from a value error, and checks a program without running it.

Exit statuses

A program that reaches its end returns status 0 to the shell. The status is the number that a script tests with $?, and it is the only information that the caller of the program receives when the program does not print anything.

status.a68
BEGIN
  print(("program finished", newline))
END

The block runs to its end, the interpreter returns, and the shell sees a successful run. The same status is returned by every program that does not stop on an error, whatever it printed along the way.

$ a68g status.a68
program finished
$ echo $?
0

A failed runtime check

A subscript outside the bounds of a row is a runtime error. The interpreter prints the offending source line, a caret under the expression, and a message, and the process ends with status 1. The statements after the failing one are not executed.

fail.a68
BEGIN
  []INT row = (1, 2, 3);
  print((row[5], newline))
END

The row has three elements and the program asks for the fifth, so the read is rejected before anything is printed. The same status 1 is returned for an arithmetic overflow, a division by zero, a false assertion, and a failed conversion of input. A shell script can test for it without knowing which check failed. The transcripts in this article show the message alone; the interpreter also prints the source line and a caret above it.

$ a68g fail.a68
a68g: runtime error: 1: index out of bounds (detected in [] "SIMPLOUT" collateral-clause starting at "(" in this line).
$ echo $?
1

Assertions

An assertion states a condition that must hold at that point. It is written ASSERT (condition);, and a false condition stops the program with the message false assertion. Assertions are for mistakes in the program, not for bad input: a failed assertion means that a caller broke a promise that the procedure relied on.

withdraw.a68
PROC withdraw = (REF INT balance, INT amount) VOID:
(
  ASSERT (amount <= balance);
  balance -:= amount
);

BEGIN
  INT balance := 100;
  withdraw(balance, 30);
  print(("balance ", whole(balance, 0), newline));
  withdraw(balance, 100);
  print(("balance ", whole(balance, 0), newline))
END

The procedure promises to subtract an amount that does not exceed the balance, and the assertion makes that promise explicit. The first call succeeds and leaves 70. The second call asks for 100 from a balance of 70, so the assertion fails before the subtraction changes anything, and the final print never runs. The condition needs its own parentheses; without them ASSERT amount <= balance is a syntax error.

$ a68g withdraw.a68
balance 70
a68g: runtime error: 1: false assertion (detected in VOID closed-clause starting at "(" in line 2).

Turning assertions off

The interpreter elaborates assertions by default, and --noassertions removes them for a run. The checks are meant for development: a release build can skip them when the cost of the tests matters or when the caller has already validated the data.

The same withdraw.a68 without assertions lets the second call through, and the balance becomes negative. The program then finishes normally, with status 0, which shows why an assertion should not be the only guard for data that comes from a user.

$ a68g --noassertions withdraw.a68
balance 70
balance -30

Stopping a program

stop ends the program immediately. It is useful when a check deep inside a procedure finds a condition that makes further work meaningless, and it returns status 0 like a normal run. A program that must tell its caller about a failure should therefore let a runtime error happen or have the caller read a message, because stop does not distinguish success from an early exit.

stop.a68
BEGIN
  print(("stopping now", newline));
  stop;
  print(("this line is not reached", newline))
END

The message before stop is printed, the message after it is not, and the shell sees status 0. This implementation also accepts abort and halt, which end the program in the same way. None of them takes an exit code, so a script that needs a particular failure status must test the program's output or arrange for a runtime error.

$ a68g stop.a68
stopping now
$ echo $?
0

Recovering from a value error

on value error(file, handler) installs a handler for a file. The handler has mode PROC (REF FILE) BOOL; returning TRUE tells the interpreter that the error has been handled, so the read returns and the program continues. The variable that was being read keeps its previous value, which is why the program below initialises it and uses a separate flag to notice the failure.

readrange.a68
PROC read in range = (INT lo, hi) INT:
(
  INT n := lo;
  BOOL bad := FALSE;
  on value error(stand in, (REF FILE f) BOOL: (bad := TRUE; TRUE));
  WHILE
    bad := FALSE;
    get(stand in, (n, newline));
    bad OR n < lo OR n > hi
  DO
    print(("expected a number from ", whole(lo, 0), " to ",
           whole(hi, 0), ", try again", newline))
  OD;
  n
);

BEGIN
  print(("Enter a number from 1 to 6:", newline));
  INT n = read in range(1, 6);
  print(("accepted ", whole(n, 0), newline))
END

The loop clears bad, reads a line, and repeats when the handler set the flag or when the number is outside the range. The handler returns TRUE after recording the failure, so the read does not stop the program. The OR is evaluated on both sides, but n is always defined because it starts at the lower bound. With the input 9, then abc, then 4, the first value is out of range, the second is not a number, and the third is accepted.

$ printf '9\nabc\n4\n' | a68g readrange.a68
Enter a number from 1 to 6:
expected a number from 1 to 6, try again
expected a number from 1 to 6, try again
accepted 4

Checking syntax without running

--check parses a source file and stops before execution. It prints nothing and returns 0 when the file is valid, and it prints the diagnostic and returns 1 when the parser rejects it. A test script can use the status to decide whether to run the program at all.

The first file is a small program that sums the numbers from 1 to 10. The second, shown below, has an initialiser with no value.

broken.a68
BEGIN
  INT total := ;
  print((total, newline))
END

The declaration has an := with no expression on its right, so the initialiser series cannot be completed. The parser reports the line of the assignment and the construct it was trying to build; no part of the program runs, so even the declaration before the error has no effect.

$ a68g --check good.a68
$ echo $?
0
$ a68g --check broken.a68
a68g: syntax error: 1: construct beginning with "BEGIN" in line 1 followed by an initialiser-series starting in line 2 and then ":=", ";", a specification in line 3, "END" in line 4 is not a valid serial-clause.
$ echo $?
1

Next steps

The reading input article covers the handlers in the context of prompts and sentinel loops, and the environment and processes article reads the exit status of another program. The big integers article shows the overflow that one of these runtime checks reports, and files explains the file values that the handlers receive.

Source

Revised Report on the Algorithmic Language Algol 68

The Algol 68 Genie project

In this article we have compared the exit status of a normal run, a failed runtime check, and a call to stop; written assertions and turned them off; recovered from a value error; and checked a program without running it.

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.