Les exceptions ont évolué en tant que généralisation des erreurs. Le premier langage de programmation à inclure un mécanisme d’exception était Lisp au début des années 1970. Il y a un bon résumé dans A Pattern of Language Evolution de Gabriel et Steele. Les exceptions (qui n'étaient pas encore appelées exceptions) découlaient de la nécessité de spécifier le comportement d'un programme en cas d'erreur. Une possibilité consiste à arrêter le programme, mais ce n'est pas toujours utile. Les implémentations de Lisp avaient traditionnellement un moyen d'entrer dans le débogueur en cas d'erreur, mais les programmeurs voulaient parfois inclure la gestion des erreurs dans leur programme. Ainsi, les implémentations Lisp des années 1960 avaient un moyen de dire «faites ceci, et si une erreur se produit, faites-le plutôt». À l'origine, les erreurs provenaient de fonctions primitives, mais les programmeurs ont trouvé pratique de déclencher délibérément une erreur afin de sauter une partie du programme et d'accéder au gestionnaire d'erreurs.
En 1972, la forme moderne de gestion des exceptions dans Lisp est apparue dans MacLisp: throw
et catch
. Le groupe de préservation de logiciels répertorie de nombreux documents sur les premières implémentations de Lisp, y compris le manuel de référence MACLISP Révision 0 de David Moon . Les primitives catch
et throw
sont documentées au §5.3 p.43.
catch
est la fonction LISP pour effectuer des sorties structurées non locales. (catch x)
évalue x
et renvoie ses valeurs, sauf que si, lors de l'évaluation, x
(throw y)
doit être évalué, catch
retourne immédiatement y
sans évaluation supplémentaire x
.
catch
peut également être utilisé avec un argument econd, non évalué, utilisé comme étiquette pour distinguer les captures imbriquées. (…)
throw
est utilisé avec catch
comme mécanisme de sortie non local structuré.
(throw x)
évalue x
et renvoie la valeur à la plus récente catch
.
(throw x <tag>)
renvoie la valeur de x
retour à la plus récente catch
étiquetée <tag>
ou non étiquetée .
L'accent est mis sur le flux de contrôle non local . C'est une forme de goto (un goto ascendant), aussi appelé saut . La métaphore est que une partie du programme lance la valeur pour retourner au gestionnaire d'exceptions, et le gestionnaire d'exception prises cette valeur et retourne.
Aujourd'hui, la plupart des langages de programmation regroupent la balise et la valeur dans un objet exception et associent le mécanisme de capture à un mécanisme de traitement.
Les exceptions ne sont pas nécessairement des erreurs. Ils sont un moyen de sortir d'un bloc de code et des blocs environnants, en s'échappant jusqu'à ce qu'un gestionnaire pour l'exception soit atteint. Qu'une telle chose soit considérée comme une "erreur" au sens intuitif est subjectif.
Certaines langues font une distinction entre les termes «erreur» et «exception». Par exemple, certains dialectes Lisp doivent à la fois throw
déclencher une exception (flux de contrôle pour les utilisateurs, destiné à effectuer une sortie non locale d’une manière qui n’indique pas que quelque chose a mal tourné) et signal
générer une erreur (ce qui indique que quelque chose a “mal tourné” et peut déclencher un événement de débogage).