scala exception either

¿Por qué `scala.util.Try` no se menciona en el capítulo" Manejo de errores sin excepciones "del libro" programación funcional en Scala "?



exception either (1)

No soy uno de los autores de la Programación Funcional en Scala, pero puedo hacer algunas conjeturas acerca de por qué no mencionan Try .

A algunas personas no les gusta la Try estándar de la biblioteca porque afirman que infringe la ley de composición de los ejecutores . Personalmente creo que este puesto es algo tonto, por las razones que Josh Suereth menciona en los comentarios de SI-6284, pero el debate resalta un aspecto importante del diseño de Try .

El map flatMap y el map flatMap están explícitamente diseñados para funcionar con funciones que pueden arrojar excepciones. Las personas de la escuela de pensamiento FPiS (incluyéndome a mí) tendería a sugerir estas funciones (si es absolutamente necesario lidiar con ellas) en versiones seguras a bajo nivel en su programa, y ​​luego exponer una API que nunca arrojará (no fatales) excepciones.

Incluir Try in your API confunde las capas de este modelo; está garantizando que sus métodos API no generarán excepciones, pero le está dando a las personas un tipo que está diseñado para ser utilizado con funciones que generan excepciones.

Sin embargo, esa es solo una queja sobre el diseño e implementación de la biblioteca estándar de Try . Es bastante fácil imaginar una versión de Try con diferente semántica, donde los métodos map y flatMap no flatMap excepciones, y aún habría buenas razones para evitar esta versión "mejorada" de Try siempre que fuera posible.

Una de estas razones es que usar Either[MyExceptionType, A] lugar de Try[A] hace que sea posible sacar más provecho de la verificación exhaustiva del compilador. Supongamos que estoy usando el siguiente ADT simple para los errores en mi aplicación:

sealed class FooAppError(message: String) extends Exception(message) case class InvalidInput(message: String) extends FooAppError(message) case class MissingField(fieldName: String) extends FooAppError( s"$fieldName field is missing" )

Ahora estoy tratando de decidir si un método que solo puede fallar en una de estas dos formas debe devolver Either[FooAppError, A] o Try[A] . Elegir Try[A] significa que estamos desechando información que es potencialmente útil tanto para los usuarios humanos como para el compilador. Supongamos que escribo un método como este:

def doSomething(result: Either[FooAppError, String]) = result match { case Right(x) => x case Left(MissingField(_)) => "bad" }

Tendré una buena advertencia en tiempo de compilación diciéndome que la coincidencia no es exhaustiva. Si agrego un caso para el error que falta, la advertencia desaparece.

Si hubiera usado Try[String] lugar, también obtendría una verificación de exhaustividad, pero la única manera de deshacerme de la advertencia sería tener un caso general: simplemente no es posible enumerar todos los Throwable s en el patrón partido.

A veces, de hecho, no podemos limitar cómodamente las formas en que una operación puede fallar a nuestro propio tipo de falla (como FooAppError anterior), y en estos casos siempre podemos usar Either[Throwable, A] . La Task de Scalaz, por ejemplo, es esencialmente una envoltura para Future[Throwable // A] . La diferencia es que Either (o // ) admite este tipo de firma, mientras que Try requiere . Y no siempre es lo que quiere, por razones como la comprobación exhaustiva útil.

En el capítulo "Manejo de errores sin excepciones" del libro "Programación funcional en Scala", el autor ofrece:

  1. El problema de arrojar excepciones del cuerpo de una función
  2. Use la Option si no nos importa la excepción real
  3. Use Either si nos preocupa la excepción real

Pero scala.util.Try no se menciona. Desde mi punto de vista, creo que Try es muy adecuado cuando nos preocupa la excepción real, ¿por qué no se menciona? ¿Hay alguna razón que me haya perdido?