KnowledgeBase 00092: Use of the ON ERROR Clause

Many QMBasic file handling statements have an optional ON ERROR clause
that can be used to capture certain error conditions that would otherwise
cause the program to abort. Most applications, however, should not need to use
this clause as the default action of QM is usually appropriate and sufficiently
informative.

General Principles

QMBasic file handling statements tend to have various combinations of four
optional error detection clauses; ON ERROR, LOCKED, THEN and ELSE. When
more than one clause is present, they must be in this order. The LOCKED clause
allows a program to detect that it would otherwise be blocked waiting for a
lock and is not discussed further here.

The THEN and ELSE clauses are found in many QMBasic statements, not just those
concerned with file handling. The THEN clause is executed if the action of the
statement is successful and the ELSE clause is executed if the action fails in
some simple way such as trying to read a record that does not exist. In many
cases such errors are valid situations in a program.

More serious errors such as detection of corruption to the internal structure
of a hashed file normally cause QM to abort the process with a descriptive
error message displayed to the user and written to the error log (if it is
enabled). Note that these are all complex error conditions that should never
occur, even as a result of errors on the part of the user or developer.

The ON ERROR clause allows a program to trap internal errors that would
otherwise cause an abort. It is highly unlikely that most applications could
perform any useful recovery action from such an error and hence the
ON ERROR clause should be very rarely needed.

One possible use for this clause might be in a web server program where failure
should display an error page on the browser. Even here, it is probably better
to implement this from the ON.ABORT VOC item rather than adding ON ERROR
clauses to every file operation in the application.

An ON ERROR clause that does nothing more than abort the program serves
no purpose and excessive use of such clauses is likely to make a program
difficult to read.

Exceptions to the Rule

There are two situations where ON ERROR clauses possibly have valid use.
Both of these are concerned with the WRITE and DELETE statements (and variants
such as WRITEV, MATWRITE or DELETEU).

Historically, with the exception of UniVerse, the Basic language used by
multivalue systems has not included a THEN/ELSE clause in WRITE or DELETE
statements. Therefore, without changing the syntax in a potentially
incompatible manner (see below), there is no way in which to return errors
such as running out of disk space when writing a record.

Without an ON ERROR clause a WRITE would abort if there is insufficient
space to complete its operation. Use of ON ERROR allows this to be
trapped.
Although this is a very unlikely situation on modern systems, it can happen
and it may be considered appropriate to code for it. Some parts of QM such as
the ED and SED editors do this so that the user can make space and try saving
the data again. Note that it is possible (though very unlikely) to run out of
disk space when deleting a record in a hashed file.

The second exception is when using pre-write or pre-delete triggers to perform
data integrity checks. Although the trigger function can detect whether the
operation being performed has an ON ERORR clause and take alternative
actions, the default behaviour is that a disallowed write or delete will cause
the ON ERROR clause to be executed, if present, aborting the program if
there is no such clause.

Why No THEN/ELSE?

It might seem reasonable for WRITE and DELETE to have an optional THEN/ELSE
clause. Changing the syntax of these statements would, however, lead to an
incompatibility that may alter the behaviour of existing programs.

Consider a simple program that maintains a record per-customer listing the
invoices open to that customer. Closing the final invoice would delete the
record. QMBasic statements to handle the update when an invoice has been
removed from the list might be

With the current syntax the ELSE pairs with the IF on the previous line such
that the record is written if not empty but deleted if empty. Changing the
syntax of WRITE to have an optional THEN/ELSE would result in the ELSE pairing
with the WRITE, leaving the old record in place when it should have been
deleted. Making THEN/ELSE mandatory on a WRITE would require big changes to
all applications.