Le eccezioni si sono evolute come generalizzazione degli errori. Il primo linguaggio di programmazione per includere un meccanismo di eccezione è stato Lisp all'inizio degli anni '70. C'è un buon riassunto in Un modello di evoluzione linguistica di Gabriel e Steele . Le eccezioni (che non erano ancora chiamate eccezioni) derivavano dalla necessità di specificare il comportamento di un programma se si verifica un errore. Una possibilità è fermare il programma, ma questo non è sempre utile. Le implementazioni Lisp tradizionalmente hanno avuto modo di inserire il debugger in un 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". Originariamente gli errori venivano dalle funzioni primitive, ma i programmatori trovavano conveniente attivare un errore deliberatamente per saltare alcune parti del programma e saltare al gestore degli errori.
Nel 1972, la forma moderna di gestione delle eccezioni in Lisp apparve su MacLisp: throw
e catch
. Il Software Preservation Group elenca un sacco di materiale sulle prime implementazioni di Lisp, tra cui The MacLISP Reference Manual Revision 0 di David Moon . I primitivi catch
e throw
sono documentati 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.
L'attenzione è sul flusso di controllo non locale . È una forma di goto (un goto verso l'alto), che è anche chiamato salto . La metafora è che una parte del programma getta il valore da restituire al gestore di eccezioni e il gestore di eccezioni prende quel valore e lo restituisce.
Oggi la maggior parte dei linguaggi di programmazione racchiude il tag e il valore in un oggetto di 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, eseguendo l'escape fino a quando non viene raggiunto un gestore per l'eccezione. Se una cosa del genere è considerata un "errore" nel senso intuitivo è soggettiva.
Alcune lingue fanno una distinzione tra i termini "errore" ed "eccezione". Ad esempio, alcuni dialetti Lisp hanno entrambi throw
per generare un'eccezione (il flusso di controllo per gli utenti, pensato per eseguire un'uscita non locale in un modo che non indica che qualcosa è andato "sbagliato") e signal
per aumentare un errore (che indica che qualcosa è andato "male" e può attivare un evento di debug).