Use of Either in Scala

Table of contents
Reading Time: 3 minutes

In this blog, we are going to see the use of Either in scala.

We use Options in scala but why do we want to go for Either?

Either is a better approach in the respect that if something fails we can track down the reason, which in Option None case is not possible.
We simply pass None but what is the reason we got None instead of Some. We will see how to tackle this scenario using Either.

Either[Left, Right]

None is similar to Left which signifies Failure and Some is similar to Right which signifies Success.

Let’s see with help of an example:

def returnEither(value: String): Either[NumberFormatException, Int] =
{
try {
Right(value.toInt)
} catch {
case ex: NumberFormatException => Left(ex)
}
}
returnEither("abc").map(x => println(x))

It will not print anything, Either is right biased and returnEither(“abc”) gives Left(java.lang.NumberFormatException: For input string: “abc”)

Now let’s call it on Right value.

returnEither("1").map(x => println(x))

It will print 1. Yes, it is right biased as the map works on Either.right. What if I want to call the map on left?

returnEither("abc").left.map(x => println(x))

It will print java.lang.NumberFormatException: For input string: “abc”.

Using Match case with Either

returnEither("1") match
{
case Right(value) => println(s"Right value: $value")
case Left(ex: NumberFormatException) => println(ex)
}

It will print Right value: 1

Extract value from Either

Let’s say we want to extract left value from Either.

println(returnEither("abc").left)

will print LeftProjection(Left(java.lang.NumberFormatException: For input string: “abc”))

println(returnEither("1").left)

will print LeftProjection(Right(1)).

println(returnEither("abc").left.get)

will give java.lang.NumberFormatException: For input string: “abc”.

println(returnEither("1").left.get)

will give: Exception in thread “main” java.util.NoSuchElementException: Either.left.get on Right

Oops. It had right value.

We can use getOrElse or fold for default value.

getOrElse

println(returnEither("1").left.getOrElse(2)) // will print 2

fold

println(returnEither("1").fold(
i => s"Found an exception: '$i'",
b => s"Found int: '$b'"
))

will print Found int: ‘1’

println(returnEither("abc").fold(
i => s"Found an exception: '$i'",
b => s"Found int: '$b'"
))

will print Found an exception: ‘java.lang.NumberFormatException: For input string: “abc”‘

Check value is Left or Right

println(returnEither("abc").isLeft) //print true
println(returnEither("1").isRight) // print true

Working with Lists using Either

val list: List[Either[Int, String]] =
List(Right("r1"), Left(0), Right("r2"), Left(10), Right("r3"), Left(100), Right("r4"))
val newList = list.map(.map(.toUpperCase))
.map(y => y.left.map(_ * 20))
println(newList)

will give List(Right(R1), Left(0), Right(R2), Left(200), Right(R3), Left(2000), Right(R4)).

Let’s understand how. As we know Either is right bias so list.map(x => x.map(.toUpperCase)), x will only have Right Values which will be converted to uppercase then as we have return type as List[Either[Int, String]] for list.map(.map(_.toUpperCase)). y will have left and right values. All the left values will be multiplied by 20.

toRight
y.toRight(x) checks if value is empty it return Left(x) else Right(y).

val ok: Either[Error, String] =
Some("Yeah!").toRight(new Error("Error!"))
val error: Either[Error, String] =
None.toRight(new Error("Error!"))
println(ok) // Right(Yeah!)
println(error) // Left(java.lang.Error: Error!)

toLeft
y.toLeft(x) checks if value is empty it return Right(x) else Left(y).

val okLeft: Either[Error, String] =
Some(new Error("Error!")).toLeft("Yeah!")
val errorLeft: Either[Error, String] =
None.toLeft("Yeah!")
println(okLeft) // Left(java.lang.Error: Error!)
println(errorLeft) // Right(Yeah!)

There could be a situation where one function is called then another and then another is a chain and the exceptions are thrown freely. How do we track which function actually caused the exception?

val array: Array[Int] = Array(0,2)
def fetchElement(el: Int): Either[Exception, Int] =
if (el < array.length ) Right(array(el))
else Left(new ArrayIndexOutOfBoundsException("from function fetchElement"))

def reciprocal(i: Int): Either[Exception, Double] =
    if (i == 0) Left(new IllegalArgumentException("from function reciprocal"))
    else Right(1.0 / i)

def stringify(d: Double): String = d.toString

def callFunctions(s: String): Either[Exception, String] =
    fetchElement(s.toInt).flatMap(reciprocal).map(stringify)

callFunctions("3") match {
    case Left(_: ArrayIndexOutOfBoundsException) => println("Exception in fetchElement")
    case Left(_: IllegalArgumentException) => println("Exception in reciprocal")
    case Left(_) => println("got unknown exception")
    case Right(s) => println(s"Got reciprocal: $s")
}

will print Exception in fetchElement
If call callFunctions(“0”) will print Exception in reciprocal

Thanks for reading!

Written by 

Jyoti Sachdeva is a software consultant with more than 6 months of experience. She likes to keep up with the trending technologies. She is familiar with languages such as C,C++,Java,Scala and is currentky working on akka,akka http and scala. Her hobbies include watching tv series and movies, reading novels and dancing.

2 thoughts on “Use of Either in Scala4 min read

Comments are closed.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading