Exceptions evolved as a generalization of errors. The first programming language to include an exception mechanism was Lisp in the early 1970s. There's a good summary in A Pattern of Language Evolution by Gabriel and Steele. Exceptions (which were not yet called exceptions) arose from the need to specify the behavior of a program if an error occurs. One possibility is to halt the program, but this is not always helpful. Lisp implementations traditionally have had a way to enter the debugger on an error, but sometimes programmers wanted to include error handling in their program. So 1960s Lisp implementations had a way to say “do this, and if an error occurs then do that instead”. Originally errors came from primitive functions, but programmers found it convenient to deliberately trigger an error in order to skip some part of the program and jump to the error handler.
In 1972, the modern form of exception handling in Lisp appeared in MacLisp: throw
and catch
. The Software Preservation Group lists a lot of material on early Lisp implementations, including The MACLISP Reference Manual Revision 0 by David Moon. The primitives catch
and throw
are documented in §5.3 p.43.
catch
is the LISP function for doing structured non-local exits. (catch x)
evaluates x
and returns its values, except that if during the evaluation of x
(throw y)
should be evaluated, catch
immediately returns y
without further evaluating x
.
catch
may also be used with a econd argument, not evaluated, which is used as a tag to distinguish between nested catches. (…)
throw
is used with catch
as a structured nonlocal exit mechanism.
(throw x)
evaluates x
and throws the value back to the most recent catch
.
(throw x <tag>)
throws the value of x
back to the most recent catch
labelled with <tag>
or unlabelled.
The focus is on nonlocal control flow. It's a form of goto (an upward-only goto), which is also called a jump. The metaphor is that one part of the program throws the value to return to the exception handler, and the exception handler catches that value and returns it.
Most programming languages today pack the tag and the value in an exception object, and combine the catching mechanism with a handling mechanism.
Exceptions are not necessarily errors. They're a way to exit from a block of code and from the surrounding blocks, escaping until a handler for the exception is reached. Whether such a thing is considered an ”error“ in the intuitive sense is subjective.
Some languages make a distinction between the terms “error” and “exception”. For example, some Lisp dialects have both throw
to raise an exception (control flow for users, meant to perform a non-local exit in a way that doesn't indicate that anything went “wrong”) and signal
to raise an error (which indicates that something went “wrong” and may trigger a debug event).
XYError
-- for instance, in Python.