Either se usa típicamente para implementar el manejo de errores rápidos. Secuenciamos los cálculos utilizando flatMap como de costumbre. Si un cálculo falla, los cálculos restantes no se ejecutan:
for {
a <- 1.asRight[String]
b <- 0.asRight[String]
c <- if(b == 0) "DIV0".asLeft[Int]
else (a / b).asRight[String]
} yield c * 100
// res21: Either[String, Int] = Left("DIV0")
Cuando usamos Either para el manejo de errores, necesitamos determinar qué tipo queremos usar para representar los errores. Podríamos usar Throwable para esto:
type Result[A] = Either[Throwable, A]
Esto nos da una semántica similar a scala.util.Try. El problema, sin embargo, es que Throwable es un tipo extremadamente amplio. No tenemos (casi) idea de qué tipo de error ocurrió.
Otro enfoque es definir un tipo de datos algebraicos para representar los errores que pueden ocurrir en nuestro programa:
object wrapper {
sealed trait LoginError extends Product with Serializable
final case class UserNotFound(username: String) extends LoginError
final case class PasswordIncorrect(username: String) extends LoginError
case object UnexpectedError extends LoginError
};
import wrapper._
case class User(username: String, password: String)
type LoginResult = Either[LoginError, User]
Este enfoque resuelve los problemas que vimos con Throwable. Nos da un conjunto fijo de tipos de errores esperados. También obtenemos la seguridad de la comprobación exhaustiva de cualquier coincidencia de patrones que hagamos:
// Choose error-handling behaviour based on type:
def handleError(error: LoginError): Unit =
error match {
case UserNotFound(u) => println(s"User not found: $u")
case PasswordIncorrect(u) => println(s"Password incorrect: $u")
case UnexpectedError => println(s"Unexpected error")
}
val result1: LoginResult = User("dave", "passw0rd").asRight
// result1: LoginResult = Right(User("dave", "passw0rd"))
val result2: LoginResult = UserNotFound("dave").asLeft
// result2: LoginResult = Left(UserNotFound("dave"))
result1.fold(handleError, println)
// User(dave,passw0rd)
result2.fold(handleError, println)
// User not found: dave