Por que a Opção / Talvez é considerada uma boa ideia e as exceções verificadas não são?

23

Algumas linguagens de programação como, por exemplo, Scala, têm o conceito de Optiontipos (também chamados Maybe), que podem conter um valor ou não.

Pelo que li sobre eles, eles são considerados amplamente uma maneira superior de lidar com esse problema null, porque forçam explicitamente o programador a considerar os casos em que pode não haver um valor em vez de apenas explodir durante o tempo de execução.

Exceções verificadas em Java, por outro lado, parecem ser uma péssima idéia, e Java parece ser a única linguagem amplamente usada que as implementa. Mas a idéia por trás deles parece ser um pouco semelhante ao Optiontipo, forçar explicitamente o programador a lidar com o fato de que uma exceção pode ser lançada.

Existem alguns problemas adicionais com exceções verificadas que os Optiontipos não possuem? Ou essas idéias não são tão parecidas quanto eu penso, e há boas razões para forçar o tratamento explícito de Opções e não de Exceções?

Cientista maluco
fonte
Veja também o Either e atipo de dados.
4
Sobre exceções verificadas: como um usuário de inúmeras bibliotecas Java de código aberto e interno, com base de código em evolução e documentos ausentes / desatualizados, estremeço ao pensar que o Java não aplicaria certas exceções a serem declaradas explicitamente. Seria um pesadelo de erros de tempo de execução sem tratamento aparecendo em lugares ruins, inesperadamente. E o Java7 finalmente torna o tratamento de exceções quase sadio, eliminando grande parte da velha confusão de try-catch.
Hyde

Respostas:

24

Porque Options são composíveis. Há uma série de métodos úteis em Optionque permitem que você escrever código conciso, permitindo ainda um controle preciso sobre o fluxo: map, flatMap, toList, flattene muito mais. Isso se deve ao fato de Optionser um tipo particular de mônada, alguns objetos que sabemos muito bem como compor. Se você não tivesse esses métodos e tivesse que padronizar a correspondência sempre Optionou ligar com isDefinedfrequência, eles não seriam tão úteis.

Em vez disso, embora as exceções verificadas adicionem alguma segurança, não há muito o que fazer com elas além de capturá-las ou deixá-las borbulhar na pilha (com o clichê adicionado na declaração de tipo).

Andrea
fonte
1
As exceções marcadas compõem mais ou menos da mesma maneira ... A diferença entre try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}e fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)é o que exatamente? Além do fato de o primeiro fornecer mais detalhes sobre o que deu errado.
User253751
14

Embora relacionados, as exceções e os objetos Talvez não lidam com o mesmo tipo de problemas.

Exceções

As exceções realmente brilham quando você precisa lidar não localmente com uma situação excepcional (que em alguns casos é um erro). Por exemplo, você está analisando um csv e deseja se proteger contra linhas com formatação incorreta. O local em que você descobre que algo está errado pode ser que algumas chamadas de função sejam afastadas da iteração da linha. Se você lançar uma exceção no nível mais profundo (onde você descobrirá sobre o problema de formatação), poderá capturá-la no loop, registrar o erro e prosseguir para a próxima linha. Você não precisa modificar nada no restante do código.

A exceção marcada adiciona muita dor, porque todas as funções intermediárias precisam declarar o tipo jogável. O recurso derrota o objetivo original, razão pela qual eles não são populares atualmente.

Talvez objetos

Talvez os objetos devam ser escolhidos quando você puder lidar localmente com uma "falha". Nesse sentido, eles substituem um código de retorno + passagem por API de referência ou um tipo anulável.

A vantagem do objeto Maybe é que você declara explicitamente que algo pode estar errado. No haskell, um objeto que não seja talvez tenha que ter um valor, caso contrário o programa não será compilado.

O problema com os tipos anuláveis ​​é que você precisa verificar se há nulo o tempo todo para ser absolutamente seguro. O estado "algo pode estar errado" é o padrão.

O problema com os códigos de retorno + pass by ref apis é que eles são menos legíveis para a maioria das pessoas.

Simon Bergot
fonte
1
@MattFenwick obrigado pelo feedback. Por que você acha que o exemplo csv não faz sentido? O OP realmente não pede técnicas de evitar clichês, e tenho a sensação de que vocabulários como funções aplicadoras e mônadas podem ser muito técnicos para essa pergunta.
Simon Bergot
1
Gostaria de salientar que, com Java (não tenho certeza de outras linguagens com exceções verificadas), os IDEs cuidam de adicionar e remover arremessos e atualizar a parte padrão dos comentários do javadoc. Portanto, pelo menos essa parte não incomoda e certamente não causa dor. Se é uma dor ou uma benção ou algo entre ao fazer design de API, isso é outro assunto ...
Hyde
5
@hyde: Só porque um IDE pode automatizar a geração de clichês inúteis não significa que um clichê inútil não é uma dor.
Michael Shaw
2
@hyde: Mas a dor não é removida. O clichê inútil ainda está lá, bagunçando o código sem motivo. Se existe um motivo para o clichê, o que é?
Michael Shaw
2
@MichaelShaw Se a exceção for inútil, remova-a: ignore a situação ou retorne o valor do erro. Se for um erro ou situação irrecuperável: use uma exceção não verificada. O que resta é tão importante quanto, por exemplo, tipos de parâmetros, e não clichês inúteis. Se for uma API incorreta na biblioteca existente, considere o método / classe do wrapper, use outra biblioteca ou apenas sofra a API incorreta.
hyde 29/03
1

porque Maybevocê pode atrasar a manipulação do erro até que você realmente precise do valor (que pode ser a falta de alguns métodos)

Considerando que a exceção verificada precisa ser tratada no local da chamada

a única vantagem das exceções é que mais informações podem ser transmitidas sobre o motivo da falha (a menos que alguém desenvolva um MaybeErrorcom um campo jogável quando houver um erro)

catraca arrepiante
fonte
2
Mas posso adiar o tratamento da exceção verificada, declarando que meu método lança essa exceção.
Scientist louco
1
@MadScientist que só vai até a pilha de chamadas, enquanto Talvez possa ir em todas as direções
catraca aberração
5
Eu acho que você não deve confundir Maybetipos com erros de manipulação. Uma exceção é usada para relatar um erro, um tipo de opção é usado para representar o resultado de uma função parcial. Uma função parcial retornada Nothingnão é um erro.
Giorgio
@MadScientist: se uma chamada de método retornar uma indicação "Valor inválido", a instrução imediatamente após a execução. Por outro lado, se um método lança uma exceção que não é capturada imediatamente, a instrução após a chamada será ignorada. Deixar as exceções verificadas percorrerem a pilha de chamadas geralmente é ruim (e não deveria ter sido a maneira 'mais fácil' de lidar com elas), pois não há como um chamador dizer se a condição tem o significado esperado pelo método que chamou, ou se representa uma condição inesperada que o método chamado está deixando borbulhar.
precisa