Exceções evoluíram como uma generalização de erros. A primeira primeira linguagem de programação a incluir um mecanismo de exceção foi Lisp no início dos anos 70. Há um bom resumo em Um padrão de evolução da linguagem por Gabriel e Steele . Exceções (que ainda não eram chamadas de exceções) surgiram da necessidade de especificar o comportamento de um programa se um erro ocorrer. Uma possibilidade é parar o programa, mas isso nem sempre é útil. As implementações do Lisp tradicionalmente tinham uma maneira de inserir o depurador em um erro, mas às vezes os programadores queriam incluir o tratamento de erros em seu programa. Então, as implementações Lisp dos anos 60 tinham uma maneira de dizer “faça isso, e se ocorrer um erro, faça isso”. Originalmente, os erros vinham de funções primitivas, mas os programadores acharam conveniente desencadear deliberadamente um erro para pular alguma parte do programa e pular para o manipulador de erros.
Em 1972, a forma moderna de tratamento de exceções no Lisp apareceu no MacLisp: throw
e catch
. O Grupo de Preservação de Software lista muito material sobre as primeiras implementações de Lisp, incluindo O Manual de Referência MACLISP Revisão 0, de David Moon . As primitivas catch
e throw
estão documentadas em § 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.
O foco está no fluxo de controle não-local . É uma forma de goto (um goto somente para cima), que também é chamado de salto . A metáfora é que uma parte do programa lança o valor para retornar ao manipulador de exceção, e o manipulador de exceção pega esse valor e o retorna.
A maioria das linguagens de programação hoje empacota a tag e o valor em um objeto de exceção e combina o mecanismo de captura com um mecanismo de manipulação.
Exceções não são necessariamente erros. Eles são uma maneira de sair de um bloco de código e dos blocos adjacentes, escapando até que um manipulador para a exceção seja atingido. Se tal coisa é considerada um "erro" no sentido intuitivo é subjetivo.
Algumas linguagens fazem uma distinção entre os termos "erro" e "exceção". Por exemplo, alguns dialetos Lisp têm throw
para gerar uma exceção (fluxo de controle para usuários, destinado a executar uma saída não local de uma maneira que não indica que algo foi "errado") e signal
para aumentar um erro (que indica que algo deu errado e pode desencadear um evento de depuração).