Scala Either
FAQ: How do I get the value out of a Scala Either
?
Solution
In this recipe I show many different ways to get the value out of a Scala Either
, while accounting for the fact that an Either
value may be a success value (a Right
) or a failure value (a Left
).
First, we start with a little setup work:
import scala.util.control.Exception.*
def makeInt(s: String): Either[Throwable, Int] =
allCatch.either(s.toInt)
val eLeft = makeInt("yo") // Left
val eRight = makeInt("42") // Right
As shown in those last comments, eLeft
is a Left
value because "yo"
cannot be converted to an Int
, and eRight
is a Right
value because "42"
can be converted.
Now let’s look at how to work with these Either
values.
Recommended approaches
These first solutions show the recommended way to work with Scala Either
values. Because you don’t initially know if an Either
is a Left
or a Right
, you have to assume that it can be either, so you work with it that way.
One solution is to use a match
expression:
val b: Int | Throwable = a match
case Right(value) => value
case Left(error) => error
Another slightly less verbose solution is to use fold
:
val b: Throwable | Int = eRight.fold(
error => error,
value => value
)
Depending on your situation, getOrElse
can be another good solution:
val b = eLeft.getOrElse(0) // 0
val b = eRight.getOrElse(0) // 42
Note that a result like 0
isn’t always the “correct” solution, because the input value may be "yo"
or it may be "0"
, and there’s no way for you to differentiate that.
Just use the Either
Also note that another usual approach is to just write your code like normal, only really worrying about the success case, and the failure case eventually takes care of itself. Somewhere in the history of Scala, someone referred to this as “Happy Path Programming,” because you just write your algorithm for the success case, and the failure case automatically takes care of itself.
So if you need to map
a value, you do that:
val c = eLeft.map(_ * 10) // Left(value = java.lang.NumberFormatException: For input string: "yo")
val c = eRight.map(_ * 10) // Right(42)
As shown, the result of a map
is another Either
, so you don’t have to deal with the issue of whether it’s a Left
or a Right
right now. That can be handled with a match
or fold
expression later.
Similarly, this is what a for
-expression looks like:
val rez = for
a <- eLeft
b = a * 10
yield
b
// Left(NumberFormatException: For input string: "yo")
val rez = for
a <- eRight
b = a * 10
yield
b
// rez: Right(420)
And notice how foreach
works:
repl> val c = eRight.foreach(println)
42
repl> val c = eLeft.foreach(println)
In the case of eLeft
, which is a Left
value, there is no output. This can be a useful approach, when you need it.
Other Right and Left solutions
I’m running out of time for today, so for now I’ll just show some more examples, with their results shown after each comment. Notice the difference between the Left
value:
eLeft.getOrElse(0) // 0
eLeft.exists(_ > 0) // false
eLeft.isLeft // true
eLeft.isRight // false
eLeft.toSeq // List()
eLeft.toSeq(0) // java.lang.IndexOutOfBoundsException: 0
eLeft.map(_ * 10) // Either[Throwable, Int] =
// Left(value = java.lang.NumberFormatException: For input string: "yo")
eLeft.canEqual(0) // false
and the Right
value in these examples:
eRight.getOrElse(0) // 42
eRight.exists(_ > 0) // true
eRight.isLeft // false
eRight.isRight // true
eRight.toSeq // List(42)
eRight.toSeq(0) // 42
eRight.map(_ * 10) // Right(420)
eRight.canEqual(0) // false
Option has many more methods
Also note that the Option
data type has many more functions than the Either
data type, so some developers like to immediately convert an Either
to an Option
, and then work with the methods on the Option
types.
Here are some success (Some
) examples:
eRight.toOption.get // 42
eRight.toOption.getOrElse(0) // 42
eRight.toOption.head // 42
eRight.toOption.headOption // Some(42)
eRight.toOption.isDefined // true
eRight.toOption.isEmpty // false
eRight.toOption.size // 1
eRight.toOption.tail // List()
eRight.toOption.take(0) // List()
eRight.toOption.toList // List(42)
And here are the failure (None
) examples:
eLeft.toOption.get // java.util.NoSuchElementException: None.get
eLeft.toOption.getOrElse(0) // 0
eLeft.toOption.head // java.util.NoSuchElementException: head of empty list
eLeft.toOption.headOption // None
eLeft.toOption.isDefined // false
eLeft.toOption.isEmpty // true
eLeft.toOption.size // 0
eLeft.toOption.tail // java.lang.UnsupportedOperationException: tail of empty list
eLeft.toOption.take(0) // List()
eLeft.toOption.toList // List()
One key here is to note all those exceptions that can be thrown when you end up with a None
. Some people try to access the value directly with get
, but if that doesn’t work, you’ll get an exception.
Summary
In summary, if you want to get the value out of a Scala Either
, I hope these examples are helpful. Also, I’ll try to update the examples at the end of this article when I have more time.