What is the difference between Try and Either?

Either does not imply success and failure, it is just a container for either an A or a B. It is common to use it to represent successes and failures, the convention being to put the failure on the left side, and the success on the right.

A Try can be seen as an Either with the left-side type set to Throwable. Try[A] would be equivalent to Either[Throwable, A].

Use Try to clearly identify a potential failure in the computation, the failure being represented by an exception. If you want to represent the failure with a different type (like a String, or a set of case classes extending a sealed trait for example) use Either.


To narrowly answer your question: "What's the semantic difference":

This probably refers to flatMap and map, which are non-existent in Either and either propagate failure or map the success value in Try. This allows, for instance, chaining like

for { 
   a <- Try {something} 
   b <- Try {somethingElse(a)}
   c <- Try {theOtherThing(b)}
} yield c

which does just what you'd hope - returns a Try containing either the first exception, or the result.

Try has lots of other useful methods, and of course its companion apply method, that make it very convenient for its intended use - exception handling.

If you really want to be overwhelmed, there are two other classes out there which may be of interest for this kind of application. Scalaz has a class called "\/" (formerly known as Prince), pronounced "Either", which is mostly like Either, but flatMap and map work on the Right value. Similarly, and not, Scalactic has an "Or" which is also similar to Either, but flatMap and map work on the Left value.

I don't recommend Scalaz for beginners.


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)

Tags:

Scala