I covered the relationship between Try
, Either
, and Option
in this answer. The highlights from there regarding the relationship between Try
and Either
are summarized below:
Try[A]
is isomorphic to Either[Throwable, A]
. In other words you can treat a Try
as an Either
with a left type of Throwable
, and you can treat any Either
that has a left type of Throwable
as a Try
. It is conventional to use Left
for failures and Right
for successes.
Of course, you can also use Either
more broadly, not only in situations with missing or exceptional values. There are other situations where Either
can help express the semantics of a simple union type (where value is one of two types).
Semantically, you might use Try
to indicate that the operation might fail. You might similarly use Either
in such a situation, especially if your "error" type is something other than Throwable
(e.g. Either[ErrorType, SuccessType]
). And then you might also use Either
when you are operating over a union type (e.g. Either[PossibleType1, PossibleType2]
).
Since Scala 2.12, the standard library does include the conversions from Either
to Try
or from Try
to Either
. For earlier versions, it is pretty simple to enrich Try
, and Either
as needed:
object TryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] =
t.map(Right(_)).recover(Left(_)).get
}
}
This would allow you to do:
import TryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)