¿Por qué Opción / Quizás se considera una buena idea y las excepciones marcadas no lo son?

23

Algunos lenguajes de programación como, por ejemplo, Scala tienen el concepto de Optiontipos (también llamados Maybe), que pueden contener un valor o no.

Por lo que he leído sobre ellos, se los considera ampliamente como una forma superior de abordar este problema null, ya que obligan explícitamente al programador a considerar los casos en los que podría no haber un valor en lugar de explotar durante el tiempo de ejecución.

Las excepciones marcadas en Java, por otro lado, parecen considerarse una mala idea, y Java parece ser el único lenguaje ampliamente utilizado que las implementa. Pero la idea detrás de ellos parece ser algo similar al Optiontipo, para obligar explícitamente al programador a lidiar con el hecho de que se puede lanzar una excepción.

¿Hay algunos problemas adicionales con las excepciones marcadas que los Optiontipos no tienen? ¿O estas ideas no son tan similares como creo, y hay buenas razones para forzar el manejo explícito de las Opciones y no de las Excepciones?

Científico loco
fuente
Ver también el Either e atipo de datos.
44
Acerca de las excepciones comprobadas: como usuario de multitud de bibliotecas Java de código abierto e internas con una base de código en evolución y documentos faltantes / desactualizados, me estremezco ante la idea de que Java no impondrá ciertas excepciones que se declararán explícitamente. Sería una pesadilla de errores de tiempo de ejecución no controlados que aparecen inesperadamente en lugares malos. Y Java7 finalmente hace que el manejo de excepciones sea casi sensato, eliminando gran parte del viejo desorden try-catch.
hyde

Respuestas:

24

Porque Option s son componibles. Hay un montón de métodos útiles en Optionque le permiten escribir código concisa, al tiempo que permite un control preciso sobre el desarrollo: map, flatMap, toList, flatteny mucho más. Esto se debe al hecho de que Optiones un tipo particular de mónada, algunos objetos que sabemos muy bien cómo componer. Si no tuviera estos métodos y tuviera que hacer coincidir los patrones siempre Option, o llamar con isDefinedfrecuencia, no serían tan útiles.

En cambio, si bien las excepciones marcadas agregan algo de seguridad, no hay mucho que pueda hacer con ellas aparte de atraparlas o dejar que se acumulen en la pila (con la placa adicional en la declaración de tipo).

Andrea
fuente
1
Las excepciones marcadas se componen más o menos de la misma manera ... La diferencia entre try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}y fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)¿qué es exactamente? Aparte del hecho de que el primero te da más detalles de lo que salió mal.
user253751
14

Si bien están relacionadas, las excepciones y los objetos Quizás no abordan el mismo tipo de problemas.

Excepciones

Las excepciones realmente brillan cuando tienes que lidiar de manera no local con una situación excepcional (que en algunos casos es un error). Por ejemplo, está analizando un csv y desea protegerse contra líneas con un formato incorrecto. El lugar donde encuentra que algo está mal puede ser algunas llamadas de función alejadas de la iteración de línea. Si lanza una excepción en el nivel más profundo (donde se entera del problema de formato), puede atraparla en el bucle, registrar el error y pasar a la siguiente línea. No tiene que modificar nada en el resto del código.

La excepción marcada agrega mucho dolor porque todas las funciones intermedias tienen que declarar el tipo arrojable. La característica derrota el propósito original, por lo que no son populares hoy en día.

Quizás objetos

Tal vez los objetos deberían ser elegidos cuando pueda lidiar localmente con un "fallo". En ese sentido, son un reemplazo para un código de retorno + paso por api de referencia o un tipo anulable.

La ventaja del objeto Maybe es que declaras explícitamente que algo puede estar mal. En haskell, un objeto que no sea tal vez debe tener un valor, de lo contrario, el programa no se compilará.

El problema con los tipos anulables es que debe verificar nulo todo el tiempo para estar absolutamente seguro. El estado "algo podría estar mal" es el predeterminado.

El problema con los códigos de retorno + apis de referencia es que son menos legibles para la mayoría de las personas.

Simon Bergot
fuente
1
@MattFenwick gracias por los comentarios. ¿Por qué crees que el ejemplo csv no tiene sentido? El OP realmente no pide técnicas para evitar repeticiones, y tengo la sensación de que el vocabulario, como el fuselaje aplicativo y las mónadas, puede ser demasiado técnico para esta pregunta.
Simon Bergot
1
Me gustaría señalar que con Java (no estoy seguro de otros lenguajes con excepciones marcadas), los IDE se encargan de agregar y eliminar tiros y actualizar la parte repetitiva de los comentarios de javadoc. Entonces, al menos esa parte no es una molestia y ciertamente no es un dolor. Ya sea que sea una molestia o una bendición o algo intermedio al hacer el diseño de la API, ese es otro asunto ...
hyde
55
@hyde: el hecho de que un IDE pueda automatizar la generación de repeticiones sin sentido no significa que la repetición no sea un problema.
Michael Shaw
2
@hyde: Pero el dolor no se elimina. La placa repetitiva sin sentido todavía está allí, abarrotando el código sin ninguna razón. Si hay una razón para el repetitivo, ¿cuál es?
Michael Shaw
2
@MichaelShaw Si la excepción no tiene sentido, elimínela: ignore la situación o devuelva el valor de error. Si se trata de un error o una situación irrecuperable: utilice una excepción no verificada. Lo que queda es tan importante como, por ejemplo, tipos de parámetros, no repetitivos sin sentido. Si es una API incorrecta en la biblioteca existente, considere el método / clase de envoltura, usar otra biblioteca o simplemente sufrir la API incorrecta.
hyde
1

porque con Maybe usted puede retrasar el manejo del error hasta que realmente necesite el valor (que puede estar a unas pocas llamadas de método)

mientras que la excepción marcada debe manejarse en la ubicación de la llamada

El único aspecto positivo de las excepciones es que se puede transmitir más información sobre por qué falló (a menos que alguien desarrolle un MaybeErrorcampo arrojable cuando se trata de un error)

monstruo de trinquete
fuente
2
Pero puedo diferir el manejo de la excepción marcada declarando que mi método arroja esta excepción.
Mad Scientist
1
@MadScientist que solo sube la pila de llamadas, mientras que Quizás puede ir en todas las direcciones
fanático de trinquete
55
Creo que no debes confundir los Maybetipos con los errores de manejo. Se usa una excepción para informar un error, se usa un tipo de opción para representar el resultado de una función parcial. El retorno parcial de una función Nothingno es un error.
Giorgio
@MadScientist: si una llamada al método devuelve una indicación de "valor no válido", la instrucción inmediatamente después de que se pueda ejecutar. Por el contrario, si un método arroja una excepción que no se detecta de inmediato, se omitirá la declaración que sigue a la llamada. Permitir que las excepciones verificadas se filtren en la pila de llamadas es generalmente malo (y no debería haber sido la forma más fácil de lidiar con ellas) ya que no hay forma de que una persona que llama sepa si la condición tiene el significado esperado por el método que llamó, o si representa una condición inesperada que el método llamado está dejando burbujear.
supercat