Joe Kearney
Joe Kearney

Reputation: 7527

scalaz: how to handle different error types in a Validation?

If I have multiple operations that return a Validation[E, _] of something with a fixed error type I can use them in a for-comprehension. For example:

val things: Validation[E, (Int, Double)] = for {
  i <- getValidationOfInt
  d <- getValidationOfDouble
} yield (i, d)

What about if the error types are different? Suppose I read from HTTP and want to convert the string response into an Int.

import scalaz._; import Scalaz._

object ValidationMixing {
  class HttpError

  def getFromHttp: Validation[HttpError, String] = ???
  def parseInt(json: String): Validation[Throwable, Int] =
    Validation.fromTryCatchNonFatal(Integer.parseInt(json))

  val intParsedFromHttp: Validation[Any, Int] = for {
    s <- getFromHttp
    i <- parseInt(s)
  } yield i
}

This compiles, but only because the error type of the Validation is Any, being a supertype of Throwable and HttpError. This isn't very helpful.

I can think of various ways of representing such a combined error type that are more useful than Any (e.g. Validation[Error1 \/ Error2, Result] to store either, Validation[String, Result] translating to an error message, etc) but they all have drawbacks.

Is there an idiomatic way to do this?

Upvotes: 3

Views: 392

Answers (1)

Ende Neu
Ende Neu

Reputation: 15783

Since nobody has had a better idea I'll leave my answer for future reference.

As said in the comment the best way is to create a error hierarchy:

trait GenericError {  /* some commond fields */}
case class MyNumericError(/* fields */)

and then use leftMap on a validation to generate appropriate errors:

Validation.fromTryCatchNonFatal(...).leftMap(t => MyNumericError(...))

This approach has two advantages

  • First you will always have a Validation[GenericError, T] so not having different types on the left part of that validation
  • The second is that this helps generate meaningful errors for both developers and service user, also note that generating an error where you have many context informations helps in this process.

Upvotes: 1

Related Questions