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: throw
e 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 catch
e throw
sono documentate in §5.3 p.43.
catch
è la funzione LISP per eseguire uscite strutturate non locali. (catch x)
valuta x
e restituisce i suoi valori, tranne che se durante la valutazione di x
(throw y)
deve essere valutato, catch
restituisce immediatamente y
senza ulteriore valutazione x
.
catch
può anche essere usato con un argomento econd, non valutato, che viene usato come tag per distinguere tra catture nidificate. (...)
throw
è usato catch
come meccanismo di uscita strutturato non locale.
(throw x)
valuta x
e riporta il valore al più recente catch
.
(throw x <tag>)
x
restituisce il valore di ritorno al più recente catch
etichettato 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 throw
sollevare 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 signal
per generare un errore (che indica che qualcosa è andato “storto” e potrebbe innescare un evento di debug).