Las excepciones evolucionaron como una generalización de errores. El primer lenguaje de programación de para incluir un mecanismo de excepción fue Lisp a principios de los años setenta. Hay un buen resumen en A Pattern of Language Evolution por Gabriel and Steele . Las excepciones (que aún no se llamaban excepciones) surgieron de la necesidad de especificar el comportamiento de un programa si se produce un error. Una posibilidad es detener el programa, pero esto no siempre es útil. Las implementaciones de Lisp tradicionalmente han tenido una forma de ingresar al depurador en un error, pero a veces los programadores querían incluir el manejo de errores en su programa. Así que las implementaciones de Lisp en la década de 1960 tenían una manera de decir "haz esto, y si ocurre un error, hazlo en su lugar". Originalmente, los errores provenían de funciones primitivas, pero los programadores consideraron conveniente desencadenar deliberadamente un error para omitir una parte del programa y saltar al controlador de errores.
En 1972, la forma moderna de manejo de excepciones en Lisp apareció en MacLisp: throw
y catch
. El Software Preservation Group enumera una gran cantidad de material sobre las primeras implementaciones de Lisp, incluyendo El Manual de referencia MACLISP Revisión 0 por David Moon . Las primitivas catch
y throw
se documentan en §5.3 p.43.
catch
es la función LISP para realizar salidas estructuradas no locales. (catch x)
evalúa x
y devuelve sus valores, excepto que si durante la evaluación de x
(throw y)
se debe evaluar, catch
devuelve y
sin evaluar más x
.
catch
también se puede usar con un segundo argumento, no evaluado, que se usa como una etiqueta para distinguir entre las capturas anidadas. (…)
throw
se usa con catch
como un mecanismo de salida no local estructurado.
(throw x)
evalúa x
y devuelve el valor al catch
más reciente.
(throw x <tag>)
devuelve el valor de x
al catch
más reciente etiquetado con <tag>
o sin etiquetar.
El foco está en el flujo de control no local . Es una forma de goto (un goto solo hacia arriba), que también se conoce como salto . La metáfora es que una parte del programa arroja el valor para volver al controlador de excepciones, y el controlador de excepciones captura ese valor y lo devuelve.
La mayoría de los lenguajes de programación de hoy empaquetan la etiqueta y el valor en un objeto de excepción, y combinan el mecanismo de captura con un mecanismo de manejo.
Las excepciones no son necesariamente errores. Son una forma de salir de un bloque de código y de los bloques circundantes, escapando hasta que se alcanza un controlador para la excepción. Si tal cosa se considera un "error" en el sentido intuitivo es subjetivo.
Algunos idiomas hacen una distinción entre los términos "error" y "excepción". Por ejemplo, algunos dialectos Lisp tienen throw
para generar una excepción (flujo de control para los usuarios, destinado a realizar una salida no local de manera que no indique que algo haya salido "mal") y signal
para aumentar un error (que indica que algo salió "mal" y puede desencadenar un evento de depuración).