Por que o tratamento de exceções é ruim?

89

A linguagem Go do Google não tem exceções como escolha de design, e a fama do Linus do Linux chama as exceções de porcaria. Por quê?

joemoe
fonte
2
O criador do ZeroMQ escreve sobre como ele acha que foi um erro escrevê-lo em C ++ (principalmente por causa do tratamento de erros) 250bpm.com/blog:4
serbaut
Go pode não ter exceções, mas tem "pânicos" dos quais você pode "se recuperar" (enquanto as instruções adiadas ainda são executadas) e que fornecem fluxo de controle não local ...
Kerrek SB
Aqui está um bom artigo lighterra.com/papers/exceptionsharmful (Exception Handling Considered Harmful)
masterxilo
Afaics, as exceções podem ser simuladas no Go com boilerplate significativo , embora este ponto possa ser mais significativo para transpilar de um açúcar de sintaxe do que para escrever o boilerplate manualmente.
Shelby Moore III

Respostas:

81

As exceções tornam realmente fácil escrever código onde uma exceção lançada quebrará invariantes e deixará objetos em um estado inconsistente. Eles essencialmente o forçam a lembrar que quase todas as afirmações que você faz podem potencialmente jogar e lidar com isso corretamente. Fazer isso pode ser complicado e contra-intuitivo.

Considere algo assim como um exemplo simples:

class Frobber
{
    int m_NumberOfFrobs;
    FrobManager m_FrobManager;

public:
    void Frob()
    {
        m_NumberOfFrobs++;

        m_FrobManager.HandleFrob(new FrobObject());
    }
};

Supondo FrobManagerque deleteo FrobObject, isso parece OK, certo? Ou talvez não ... Imagine então se FrobManager::HandleFrob()ou operator newlança uma exceção. Neste exemplo, o incremento de m_NumberOfFrobsnão é revertido. Portanto, qualquer pessoa que use essa instância de Frobberterá um objeto possivelmente corrompido.

Este exemplo pode parecer estúpido (ok, eu tive que me esforçar um pouco para construir um :-)), mas, a conclusão é que se um programador não está pensando constantemente em exceções e certificando-se de que todas as permutações de estado sejam roladas sempre que houver lançamentos, você terá problemas dessa forma.

Por exemplo, você pode pensar nisso como você pensa em mutexes. Dentro de uma seção crítica, você confia em várias instruções para garantir que as estruturas de dados não sejam corrompidas e que outros threads não possam ver seus valores intermediários. Se qualquer uma dessas declarações simplesmente não funcionar, você terminará em um mundo de dor. Agora tire os bloqueios e a simultaneidade e pense em cada método assim. Pense em cada método como uma transação de permutações no estado do objeto, se quiser. No início da chamada do método, o objeto deve estar em estado limpo e, no final, também deve haver um estado limpo. No meio, a variável foopode ser inconsistente combar, mas seu código acabará corrigindo isso. O que as exceções significam é que qualquer uma de suas declarações pode interrompê-lo a qualquer momento. A responsabilidade recai sobre você em cada método individual para acertar e reverter quando isso acontecer, ou ordenar suas operações para que os lançamentos não afetem o estado do objeto. Se você errar (e é fácil cometer esse tipo de erro), o chamador acaba vendo seus valores intermediários.

Métodos como o RAII, que os programadores de C ++ adoram mencionar como a solução definitiva para esse problema, ajudam muito na proteção contra isso. Mas eles não são uma bala de prata. Isso garante que você libere recursos imediatamente, mas não o livra de ter que pensar sobre a corrupção do estado do objeto e os chamadores vendo valores intermediários. Então, para muitas pessoas, é mais fácil dizer, por decreto de estilo de codificação, sem exceções . Se você restringir o tipo de código que escreve, é mais difícil introduzir esses bugs. Do contrário, é muito fácil cometer um erro.

Livros inteiros foram escritos sobre codificação segura de exceção em C ++. Muitos especialistas erraram. Se for realmente tão complexo e tiver tantas nuances, talvez seja um bom sinal de que você precisa ignorar esse recurso. :-)

Asveikau
fonte
9
Resposta interessante, porém não reflete nada em minha experiência de programação. Portanto, acho que é específico da cultura (talvez mais um problema em Java ou C ++ do que, digamos, Python) ou específico do domínio.
ddaa
39
As exceções escritas em uma linguagem gerenciada usando um padrão try-catch-finally nunca devem deixar um estado inválido se forem escritas corretamente; como o bloco finally tem garantia de execução, os objetos podem ser desalocados lá. O resto deve ser cuidado por variáveis ​​que saem do escopo e coleta de lixo.
Robert Harvey
7
@ddaa O problema é definitivamente possível em Python. O resultado é normalmente um bug difícil de reproduzir. Talvez você tenha sido especialmente meticuloso ou sortudo. Mas então, você está certo de que é mais um problema em C ++, onde o bug mais comum de EH pobre é um vazamento de memória. Tentei enfatizar que os vazamentos não são o problema mais sério. @Robert GC atenuará vazamentos de memória, mas não tenho certeza se o código gerenciado o livrará de erros de programador. Em particular, se alguém não está prestando atenção à segurança da exceção porque não acha que isso seja um problema em seu idioma, isso não é um bom sinal.
asveikau
4
@lzprgmr certamente existem: exceções permitem que você lide com diff. tipos de erros no diff. coloca no código. Lidar com um erro de conexão pode exigir uma reconexão, mas não no meio de uma função profundamente aninhada. Você quer enviar isso para o gerenciador de conexões ou algo assim. Em seguida, lidar com os valores de retorno força você a verificar os erros em cada chamada e fazer isso manualmente (no caso de um erro de redefinição de conexão, por exemplo). Além disso, os valores de retorno se acumulam em chamadas aninhadas: func3 pode retornar -1, func2 chama func3, retorna -2 em seus erros, -1 para func3's, etc.
abourget
3
Eu estava votando contra, mas inverti porque esse é o motivo pelo qual as exceções são desprezadas. No entanto, em minha opinião, quase qualquer método ou código pode falhar. Você não pode lidar com cada condição de erro introduzindo um valor de retorno para ela. Você perderá informações sobre o erro. Pensar que você pode manter tudo bem sincronizado verificando cada instrução e fazendo a limpeza leva a um código muito complicado - detectar um erro em várias instruções e limpar um ou dois recursos que não são GC é muito mais limpo.
Maarten Bodewes
50

O motivo de Go não ter exceções é explicado nas Perguntas frequentes sobre o design da linguagem Go:

As exceções são uma história semelhante. Vários designs de exceções foram propostos, mas cada um adiciona uma complexidade significativa à linguagem e ao tempo de execução. Por sua própria natureza, as exceções abrangem funções e talvez até goroutines; eles têm implicações abrangentes. Também há preocupação com o efeito que eles teriam nas bibliotecas. Eles são, por definição, excepcionais, mas a experiência com outras linguagens que os suportam mostra que eles têm um efeito profundo na biblioteca e na especificação de interface. Seria bom encontrar um design que os permitisse ser verdadeiramente excepcionais sem encorajar erros comuns a se transformarem em um fluxo de controle especial que requer que cada programador compense.

Como os genéricos, as exceções permanecem um problema em aberto.

Em outras palavras, eles ainda não descobriram como oferecer suporte a exceções no Go de uma forma que considerem satisfatória. Eles não estão dizendo que as exceções são ruins em si ;

ATUALIZAÇÃO - maio de 2012

Os designers de Go agora pularam da cerca. Seu FAQ agora diz o seguinte:

Acreditamos que as exceções de acoplamento a uma estrutura de controle, como no idioma try-catch-finally, resultam em código complicado. Também tende a encorajar os programadores a rotular muitos erros comuns, como a falha ao abrir um arquivo, como excepcionais.

Go tem uma abordagem diferente. Para tratamento de erros simples, os retornos de vários valores do Go tornam mais fácil relatar um erro sem sobrecarregar o valor de retorno. Um tipo de erro canônico, juntamente com outros recursos do Go, torna o tratamento de erros agradável, mas bastante diferente daquele em outras linguagens.

Go também possui algumas funções integradas para sinalizar e se recuperar de condições verdadeiramente excepcionais. O mecanismo de recuperação é executado apenas como parte do estado de uma função sendo destruído após um erro, o que é suficiente para lidar com a catástrofe, mas não requer estruturas de controle extras e, quando bem usado, pode resultar em código de tratamento de erros limpo.

Consulte o artigo Adiar, entrar em pânico e recuperar para obter detalhes.

Portanto, a resposta curta é que eles podem fazer isso de maneira diferente, usando o retorno de vários valores. (E eles têm uma forma de tratamento de exceção de qualquer maneira.)


... e a fama do Linus do Linux chamou de merda de exceções.

Se você quer saber por que Linus acha que as exceções são uma porcaria, a melhor coisa é procurar seus escritos sobre o assunto. A única coisa que rastreei até agora é esta citação que está embutida em alguns e-mails em C ++ :

"Todo o tratamento de exceções do C ++ está fundamentalmente quebrado. Está especialmente quebrado para kernels."

Você notará que ele está falando sobre exceções C ++ em particular, e não exceções em geral. (E exceções C ++ que aparentemente têm algumas questões que tornam complicado para usar corretamente.)

Minha conclusão é que Linus não chamou as exceções (em geral) de "merda" de forma alguma!

Stephen C
fonte
30
Eu odeio quando eles escondem informações colocando-as no FAQ. :)
brian d foy
7
Observe que Linus começa aquele e-mail com "C ++ é uma linguagem horrível." e continua a reclamar sobre o quanto ele odeia o C ++ e as pessoas que optam por programar nele. Conseqüentemente, não acho que sua opinião sobre as exceções do C ++ possa ser considerada confiável, dada sua opinião um tanto tendenciosa em relação ao C ++.
Pharap
1
@ Hi-Angel - Como diz o texto que citei: "Para tratamento de erros simples, os retornos de vários valores do Go tornam mais fácil relatar um erro sem sobrecarregar o valor de retorno." . É assim que está relacionado. De qualquer forma, estou citando a lógica dos designers da Go. Se você quiser discutir, argumente com eles >>.
Stephen C
1
@ Hi-Angel - Eu não escrevi esses parágrafos. Eu apenas os citei. Se você tiver algum problema com eles, provavelmente deveria conversar com os autores. Em teoria, eu poderia ter fornecido um tutorial sobre a linguagem Go como contexto. Mas, para ser franco, as pessoas que não entendem a terminologia Go podem visitar o site Go para descobrir o que isso significa.
Stephen C,
1
".. resulta em código complicado" Há muito tempo, escrevi um programa C com muitas operações de string. Cada método foi alocar memória e, em seguida, verificar se a alocação foi bem-sucedida. Parecia que a maioria do código estava apenas verificando as alocações. Não é complicado? C ++ com exceções foi um grande resgate para mim.
robsosno,
29

As exceções não são ruins em si, mas se você sabe que vão acontecer com frequência, elas podem ser caras em termos de desempenho.

A regra prática é que as exceções devem sinalizar condições excepcionais e que você não deve usá-las para controlar o fluxo do programa.

Robert Harvey
fonte
9
@Robert: "você não deve usá-los para controlar o fluxo do programa", não pensei nisso dessa forma, uma nova perspectiva para mim: P +1
okw
2
Também depende muito do idioma. É difícil evitar exceções se você estiver programando em Java, por exemplo.
Charles Salvia
2
@Charles: Acho que o ponto é que as exceções são apropriadas em situações que indicam um bug, sistema mal configurado ou entradas irracionais. A maioria das exceções da biblioteca Java pode ser evitada no código de "fluxo de trabalho normal".
Artelius
6
eles não precisam custar muito. por exemplo, você pode implementar um "teste" que custa tempo de execução zero e "lançar" manipuladores de exceção em uma tabela com base nos endereços do chamador que ele vê na pilha ... Eu diria que os maiores motivos para não as exceções de uso não estão relacionadas ao desempenho.
asveikau
Reformulado; a questão claramente sugere o uso de exceções em geral, ou de não usar exceções (elas são uma porcaria ou nem mesmo estão na língua). Sua resposta mostra apenas por que as exceções são ruins para o desempenho quando usadas para o fluxo de controle do programa.
Maarten Bodewes
26

Eu discordo com "apenas lance exceções em uma situação excepcional." Embora geralmente seja verdade, é enganoso. As exceções são para condições de erro (falhas de execução).

Independentemente da linguagem que você usa, adquira uma cópia do Framework Design Guidelines : Conventions, Idioms, and Patterns for Reusable .NET Libraries (2ª edição). O capítulo sobre lançamento de exceções não tem par. Algumas citações da primeira edição (a 2ª no meu trabalho):

  • NÃO retorne códigos de erro.
  • Os códigos de erro podem ser facilmente ignorados, e frequentemente são.
  • As exceções são o principal meio de relatar erros em estruturas.
  • Uma boa regra prática é que se um método não faz o que seu nome sugere, ele deve ser considerado uma falha no nível do método, resultando em uma exceção.
  • NÃO use exceções para o fluxo normal de controle, se possível.

Existem páginas de notas sobre os benefícios das exceções (consistência da API, escolha do local do código de tratamento de erros, robustez aprimorada etc.). Há uma seção sobre desempenho que inclui vários padrões (Tester-Doer, Try-Parse).

Exceções e tratamento de exceções não são ruins. Como qualquer outro recurso, eles podem ser mal utilizados.

TrueWill
fonte
3
Eu tenho que discordar disso. Não sou contra exceções, e esse livro é obrigatório, no entanto, é voltado para o desenvolvimento .NET e C #.
3
Eu sei que isso é antigo, só queria comentar que parece que haveria um desacordo geral de estilo entre o tipo .NET e o tipo * nix. Todas as bibliotecas que usei como dev Linux usam códigos de retorno e guias de estilo * nix que li (como os da minha empresa e do Google, por exemplo) simplesmente dizem "não fazemos exceções". Apenas pense que é interessante.
jarvisteve
1
As estruturas devem tratar as exceções de maneira diferente dos aplicativos do usuário final. Os frameworks não têm uma maneira de lidar com erros além de lançar uma exceção, os aplicativos de consumidor sim.
0x6C38
11

Da perspectiva do golang, acho que não ter tratamento de exceções mantém o processo de compilação simples e seguro.

Da perspectiva de Linus, eu entendo que o código do kernel é TUDO sobre casos extremos. Portanto, faz sentido recusar exceções.

Exceções fazem sentido no código onde não há problema em deixar a tarefa atual no chão e onde o código de caso comum tem mais importância do que o tratamento de erros. Mas eles requerem a geração de código do compilador.

Por exemplo, eles são bons na maioria dos códigos voltados para o usuário de alto nível, como códigos de aplicativos da Web e de desktop.

ddaa
fonte
Mas o que é verdade para o código do kernel também é verdade para processos de servidor nativos de longa execução.
Lothar
11

As exceções em si não são "ruins"; é a maneira como as exceções às vezes são tratadas que tende a ser ruim. Existem várias diretrizes que podem ser aplicadas ao lidar com exceções para ajudar a aliviar alguns desses problemas. Alguns deles incluem (mas certamente não estão limitados a):

  1. Não use exceções para controlar o fluxo do programa - ou seja, não confie em instruções "catch" para alterar o fluxo da lógica. Isso não apenas tende a ocultar vários detalhes em torno da lógica, mas pode levar a um desempenho ruim.
  2. Não lance exceções de dentro de uma função quando um "status" retornado faria mais sentido - lance apenas exceções em uma situação excepcional. A criação de exceções é uma operação cara e de alto desempenho. Por exemplo, se você chamar um método para abrir um arquivo e esse arquivo não existir, lance uma exceção "FileNotFound". Se você chamar um método que determina se existe uma conta de cliente, retorne um valor booleano, não retorne uma exceção "CustomerNotFound".
  3. Ao determinar se deve ou não tratar uma exceção, não use uma cláusula "try ... catch" a menos que você possa fazer algo útil com a exceção. Se você não for capaz de lidar com a exceção, deve apenas deixá-la borbulhar na pilha de chamadas. Caso contrário, as exceções podem ser "engolidas" pelo manipulador e os detalhes serão perdidos (a menos que você relembre a exceção).
Jeff Bramwell
fonte
2
Retornar ao status é uma coisa complicada. Já vi muitos códigos com um método GetCustomer retornando uma entidade Customer em caso de sucesso ou null em caso de falha. Em vários casos, o código de chamada nunca verificou o resultado, mas acessou imediatamente o Cliente. Isso funcionou na maioria das vezes ...
TrueWill de
3
Mas se GetCustomer lançar uma exceção em vez de retornar nulo, o código do cliente ainda precisará manipular a exceção. Seja verificando o nulo ou manipulando exceções, a responsabilidade recai sobre o código do cliente - se ele não fizer as coisas de maneira adequada, cedo ou tarde algo explodirá.
Chris
1
@TrueWill As linguagens que oferecem suporte a modelos / genéricos resolvem isso retornando um em Option<T>vez de nullhoje em dia. Acabei de ser introduzido no Java 8, por exemplo, pegando uma dica do Guava (e outros).
Maarten Bodewes
@owlstead Sim. Ame a talvez mônada. Esse é um bom caminho a percorrer se sua linguagem suportar e oferecer correspondência de padrões.
TrueWill
@owlstead Novamente, o que Chris disse ainda é válido para isso - o usuário deve se lembrar de chamar a função .orElse (defaultObject), ou qualquer idioma que o idioma em questão tenha decidido. No final do dia, são os programadores que são o problema, e não o método de tratamento de erros.
Pharap de
9

Os argumentos típicos são que não há como saber quais exceções sairão de uma parte específica do código (dependendo da linguagem) e que elas são muito parecidas com gotos, tornando difícil rastrear mentalmente a execução.

http://www.joelonsoftware.com/items/2003/10/13.html

Definitivamente, não há consenso sobre esse assunto. Eu diria que, do ponto de vista de um programador C hard-core como Linus, exceções são definitivamente uma má ideia. No entanto, um programador Java típico está em uma situação muito diferente.

Tim Sylvester
fonte
1
O código C tem uma espécie de exceções, apenas de uma maneira diferente. Você precisa envolver todas as chamadas para uma função não trivial em ifs, o que torna o uso dessa linguagem uma dor de cabeça!
RCIX
1
Também existe o setjmp/ longjmp, o que é muito ruim.
Tim Sylvester
9
Você realmente deseja seguir o conselho de um homem que valoriza os programadores de fita adesiva e que não acredita que testes de unidade sejam necessários? joelonsoftware.com/items/2009/09/23.html
TrueWill
4
Este é o erro clássico (ou trapaça) em uma discussão em que argumentos sobre o assunto são substituídos por referências de personalidade. Isso geralmente é um sinal de discussão degenerada.
Petr Gladkikh
1
@PetrGladkikh A discussão começou com o OP referindo-se à opinião de Linus ... essa trapaça é conhecida como a falácia do apelo à autoridade. A discussão só pode subir a partir daí, e não é "trapaça" responder à pergunta de por que Linus não gosta de exceções referindo-se à sua personalidade.
Jim Balter
7

As exceções não são ruins. Eles se encaixam bem no modelo RAII do C ++, que é a coisa mais elegante do C ++. Se você já tem um monte de código que não é seguro para exceções, eles são ruins nesse contexto. Se você está escrevendo um software de baixo nível, como o sistema operacional Linux, eles são ruins. Se você gosta de bagunçar seu código com um monte de verificações de retorno de erro, então eles não ajudam. Se você não tem um plano para controle de recursos quando uma exceção é lançada (que os destruidores C ++ fornecem), então eles são ruins.

Paulo
fonte
7
RAII é útil mesmo sem exceções.
Mark Ransom
4
no entanto, as exceções não são úteis sem RAII (ou algum outro gerenciamento automático de recursos).
Greg Rogers
1 para apontar situações onde as exceções não são apropriadas e que as exceções não são inerentemente ruins.
Pharap de
4

Um ótimo caso de uso para exceções é, portanto ...

Digamos que você esteja em um projeto e cada controlador (cerca de 20 controladores principais diferentes) estenda um único controlador de superclasse com um método de ação. Então, cada controlador faz um monte de coisas diferentes entre si chamando os objetos B, C, D em um caso e F, G, D em outro caso. As exceções vêm ao resgate aqui em muitos casos onde havia toneladas de código de retorno e CADA controlador estava lidando com isso de forma diferente. Eu destruí todo aquele código, lancei a exceção apropriada de "D", peguei no método de ação do controlador da superclasse e agora todos os nossos controladores são consistentes. Anteriormente, D estava retornando nulo para VÁRIOS casos de erro diferentes que desejamos informar ao usuário final, mas não foi possível e eu não fiz

sim, temos que nos preocupar com cada nível e qualquer limpeza / vazamento de recursos, mas em geral nenhum de nossos controladores tinha quaisquer recursos para limpar depois.

graças a Deus nós tínhamos exceções ou eu teria que refatorar e perder muito tempo em algo que deveria ser um simples problema de programação.

Dean Hiller
fonte
1
1 Facilmente um dos melhores argumentos para usar exceções que eu li. Poderia ter usado exemplos mais detalhados (ou seja, um diagrama UML, algum pseudocódigo ou algum código real), mas o ponto sobre como fazer as subclasses funcionarem consistentemente é bom. Além disso, o fato de sua evidência ser anedótica mostra que as exceções são úteis em situações reais, e a utilidade é o objetivo principal de qualquer recurso de linguagem.
Pharap
apenas como uma adição, se você estiver no scala, você pode retornar Try [ResponseType] que representa uma exceção ou resposta real. Você pode, então, seguir o mesmo padrão que evitei acima, sem exceções reais, exceto aquelas que são colocadas na tentativa. Então é como se todo método que você tivesse retornasse 1 + n tipos de resposta que eu acho que são necessários. No entanto, em scala, retornamos Future [response], que funciona de forma muito semelhante ao Try, mas pode ajudar com uma programação mais assíncrona.
Dean Hiller
2

Teoricamente, eles são muito ruins. No mundo matemático perfeito, você não pode obter situações de exceção. Observe as linguagens funcionais, elas não têm efeitos colaterais, portanto, virtualmente não têm origem para situações comuns.

Mas, a realidade é outra história. Sempre temos situações que são "inesperadas". É por isso que precisamos de exceções.

Acho que podemos pensar em exceções como sintaxe de açúcar para ExceptionSituationObserver. Você apenas recebe notificações de exceções. Nada mais.

Com Go, acho que eles introduzirão algo que lidará com situações "inesperadas". Posso supor que eles tentarão fazer com que soe menos destrutivo como exceções e mais como lógica de aplicativo. Mas isso é apenas meu palpite.

Mike Chaliy
fonte
2
"Olhe para as linguagens funcionais, elas não têm efeitos colaterais, portanto, virtualmente não têm origem para situações comuns." Isso é um exagero grosseiro.
Stephen C de
3
O que é 5/0 em matemática? Arcsin (200)? Sqrt (-1)? O Math tem muitas situações excepcionais.
Robert Fraser
3
Estas não são situações executivas ... elas simplesmente não têm significado ... e por causa disso, podem ser implementadas como exceções ... mas também podem ser implementadas como frascos de pré-condições .. então, depende da implementação técnica.
Mike Chaliy
3
@MikeChaliy - Sinto muito, mas isso é apenas sofisma. Você pode aplicar esse tipo de raciocínio para dizer que NÃO há situações de exceção em nada, NUNCA. Na realidade, expressões matemáticas que não têm significado (ou que não têm valor definido) SÃO excepcionais. Isso não significa que eles precisam ser tratados lançando e capturando exceções ... mas se você não fizer isso, precisará de valores especiais (como Inf e Nan) ou de operações que retornem vários valores. Em suma, esses casos requerem algum tipo de tratamento especial.
Stephen C de
1
Os computadores são máquinas de estado. Não é um mundo matemático perfeito.
Arunav Sanyal
1

O paradigma de tratamento de exceções do C ++, que forma uma base parcial para o do Java e, por sua vez, .net, apresenta alguns bons conceitos, mas também tem algumas limitações severas. Uma das principais intenções de design do tratamento de exceção é permitir que os métodos garantam que eles irão satisfazer suas pós-condições ou lançar uma exceção, e também garantir que qualquer limpeza que precise acontecer antes que um método possa sair, aconteça. Infelizmente, os paradigmas de tratamento de exceções de C ++, Java e .net falham em fornecer qualquer bom meio de lidar com a situação em que fatores inesperados impedem que a limpeza esperada seja realizada. Isso, por sua vez, significa que se deve correr o risco de ter tudo parando bruscamente se algo inesperado acontecer (a abordagem C ++ para lidar com uma exceção ocorre durante o desenrolamento da pilha),

Mesmo que o tratamento de exceções seja geralmente bom, não é irracional considerar inaceitável um paradigma de tratamento de exceções que falha em fornecer um bom meio para lidar com problemas que ocorrem durante a limpeza após outros problemas. Isso não quer dizer que uma estrutura não pudesse ser projetada com um paradigma de tratamento de exceções que pudesse garantir um comportamento sensato mesmo em cenários de falha múltipla, mas nenhuma das principais linguagens ou estruturas ainda pode fazer isso.

supergato
fonte
1

Não li todas as outras respostas, então isso pode já ter sido mencionado, mas uma crítica é que eles fazem com que os programas quebrem em longas cadeias, tornando difícil rastrear erros ao depurar o código. Por exemplo, se Foo () chama Bar () que chama Wah () que chama ToString (), então acidentalmente enviar os dados errados para ToString () acaba parecendo um erro em Foo (), uma função quase completamente não relacionada.

kingfrito_5005
fonte
0
  • A exceção não tratada é geralmente ruim.
  • Exceção mal tratada é ruim (claro).
  • A 'bondade / maldade' do tratamento de exceções depende do contexto / escopo e da adequação, e não por causa disso.
okw
fonte
0

Ok, resposta chata aqui. Acho que realmente depende do idioma. Quando uma exceção pode deixar recursos alocados para trás, eles devem ser evitados. Em linguagens de script, eles simplesmente abandonam ou superam partes do fluxo do aplicativo. Isso é desagradável em si, mas escapar de erros quase fatais com exceções é uma ideia aceitável.

Para sinalização de erro, geralmente prefiro sinais de erro. Tudo depende da API, do caso de uso e da gravidade ou se o registro for suficiente. Também estou tentando redefinir o comportamento e, em throw Phonebooks()vez disso. A ideia é que "Exceções" geralmente são becos sem saída, mas uma "Lista telefônica" contém informações úteis sobre recuperação de erros ou rotas de execução alternativas. (Não encontrei um bom caso de uso ainda, mas continue tentando.)

mario
fonte
0

Para mim, a questão é muito simples. Muitos programadores usam o manipulador de exceções de forma inadequada. Mais recursos de linguagem é melhor. Ser capaz de lidar com exceções é bom. Um exemplo de mau uso é um valor que deve ser inteiro não verificado, ou outra entrada que pode ser dividida e não verificada para divisão de zero ... o tratamento de exceções pode ser uma maneira fácil de evitar mais trabalho e raciocínio, o programador pode querer fazer um atalho sujo e aplicar um tratamento de exceção ... A declaração: "um código profissional NUNCA falha" pode ser ilusória, se alguns dos problemas processados ​​pelo algoritmo forem incertos por sua própria natureza. Talvez nas situações desconhecidas por natureza seja bom entrar em cena o tratador de exceções. Boas práticas de programação são uma questão de debate.

iuri
fonte
A questão não é (ou não deveria ser) se o código pode falhar - um problema maior é até que ponto, se o código falhar, a pessoa se preocupa com os detalhes. Se alguém tenta carregar um documento e um dos métodos de "leitura de dados" falha, muitas vezes não se importa qual deles, já que o efeito é o mesmo de qualquer maneira: o documento não pode ser carregado. Conceitualmente, o tratamento de exceções deve ser bom para isso. O problema é que os paradigmas de manipulação de exceções do .NET e Java não fornecem nenhuma maneira agradável de distinguir exceções "chatas" que devem ser agrupadas das que não devem.
supercat