Le eccezioni si sono evolute come generalizzazione degli errori. Il primo linguaggio di programmazione a includere un meccanismo di eccezione fu Lisp nei primi anni '70. C'è un buon riassunto in A Pattern of Language Evolution di Gabriel e Steele. Eccezioni (che non erano ancora chiamate eccezioni) derivavano dalla necessità di specificare il comportamento di un programma in caso di errore. Una possibilità è di interrompere il programma, ma ciò non è sempre utile. Le implementazioni di Lisp hanno tradizionalmente un modo per inserire il debugger in caso di errore, ma a volte i programmatori volevano includere la gestione degli errori nel loro programma. Quindi le implementazioni Lisp degli anni '60 avevano un modo per dire "fai questo, e se si verifica un errore, fallo invece". Inizialmente gli errori venivano dalle funzioni primitive, ma i programmatori trovavano conveniente innescare deliberatamente un errore per saltare una parte del programma e passare al gestore degli errori.
Nel 1972, la forma moderna di gestione delle eccezioni in Lisp è apparsa in MacLisp: throwe catch. Il Software Preservation Group elenca molto materiale sulle prime implementazioni di Lisp, incluso The MACLISP Reference Manual Revision 0 di David Moon . Le primitive catche throwsono documentate in §5.3 p.43.
catchè la funzione LISP per eseguire uscite strutturate non locali. (catch x)valuta xe restituisce i suoi valori, tranne che se durante la valutazione di x (throw y)deve essere valutato, catchrestituisce immediatamente ysenza ulteriore valutazione x.
catchpuò anche essere usato con un argomento econd, non valutato, che viene usato come tag per distinguere tra catture nidificate. (...)
throwè usato catchcome meccanismo di uscita strutturato non locale.
(throw x)valuta xe riporta il valore al più recente catch.
(throw x <tag>)xrestituisce il valore di ritorno al più recente catchetichettato con <tag>o senza etichetta.
L'attenzione si concentra sul flusso di controllo non locale . È una forma di goto (un goto solo verso l'alto), che è anche chiamato un salto . La metafora è che una parte del programma getta il valore per tornare al gestore di eccezioni, e il gestore di eccezioni catture tale valore e lo restituisce.
La maggior parte dei linguaggi di programmazione oggi racchiude il tag e il valore in un oggetto eccezione e combina il meccanismo di cattura con un meccanismo di gestione.
Le eccezioni non sono necessariamente errori. Sono un modo per uscire da un blocco di codice e dai blocchi circostanti, scappando fino a raggiungere un gestore per l'eccezione. Se una cosa del genere sia considerata un "errore" in senso intuitivo è soggettivo.
Alcune lingue fanno una distinzione tra i termini "errore" e "eccezione". Ad esempio, alcuni dialetti Lisp devono entrambi throwsollevare un'eccezione (flusso di controllo per gli utenti, inteso per eseguire un'uscita non locale in un modo che non indica che qualcosa è andato “storto”) e signalper generare un errore (che indica che qualcosa è andato “storto” e potrebbe innescare un evento di debug).