In our previous blog, we have seen how we can handle exceptions using try/catch and Try block.  In this blog, we will explore how we can handle exceptions using Either.

Either, just like a Try, is also a container type which can have one value either Left or Right at a time. We can also use Option to handle exceptions but if an exception occurs returning None, it will not give enough information about the reason for the failure. Either has two parts i.e Left and Right. Left and Right are case classes which inherit from Either. Left part contains the exceptions and Right contains the success value.

Let’s take an example,

scala> def divide(numerator: Int, denominator: Int): Either[String, Int] = {
     | if (denominator == 0)
     | Left("Denominator can not be zero")
     | else
     | Right(numerator / denominator)
     | }
divide: (numerator: Int, denominator: Int)Either[String,Int]

Notice the return type of divide method is Either[String, Int]. Left part contains the error message and Right part contains the success value.

Let’s try with the positive and negative value of denominator,

scala> divide(5, 0)
res0: scala.util.Either[String,Int] = Left(Denominator can not be zero)

scala> divide(15, 5)
res1: scala.util.Either[String,Int] = Right(3)

 So, it is working fine. Now how to decide whether Either has left or right result.  Either provides two methods isLeft and isRight to check which type of value Either holds.

scala> def useResult(result: Either[String, Int]) = {
     | if (result.isLeft)
     | println("Left: it contains exception message")
     | else
     | println("Right: it contains success value")
     | }
useResult: (result: Either[String,Int])Unit

scala> useResult(divide(14, 7))
Right: it contains success value

scala> useResult(divide(14, 0))
Left: it contains exception message

How to get values from Either?

There are many ways we will talk about all one by one.  One way to get values is by doing left and right projection. We can not perform any operation i.e, map, filter etc; on Either. Either provide left and right methods to get the left and right projection. Projection on either allows us to apply functions like map, filter etc.

For example,

scala> val div = divide(14, 7)
div: scala.util.Either[String,Int] = Right(2)

scala> div.right
res1: scala.util.Either.RightProjection[String,Int] = RightProjection(Right(2))

When we applied right on either, it returned RightProjection. Now we can extract the value from right projection using get, but if there is no value the compiler will blow up using get. So, we can use getOrElse to make sure compiler does not blow up if there is no value.

scala> div.right.get
res2: Int = 2

scala> div.left.getOrElse("There is no error message")
res3: String = There is no error message

We can get values after checking whether either has value in left or right.

scala> def getValuesFromEither(result: Either[String, Int]) = {
     |   if (result.isLeft)
     |     println(s"Error: ${result.left.get}")
     |   else
     |     println(s"Value after divison: ${result.right.get}")
     | }
getValuesFromEither: (result: Either[String,Int])Unit

scala> getValuesFromEither(divide(5,0))
Error: Denominator can not be zero

scala> getValuesFromEither(divide(55,5))
Value after divison: 11

Though we got the value from either but code is not elegant. We are first querying it whether it is left or right and then getting the value from it. Can we have the better way to do this? Yes, pattern matching is very powerful and elegant way to get the value. Let’s try it with pattern matching.

scala> def showResult(result: Either[String, Int]) = {
     | result match {
     | case Left(error) => println(s"Error: $error")
     | case Right(value) => println(s"Value after divison $value")
     | }
     | }
showResult: (result: Either[String,Int])Unit

scala> showResult(divide(16, 4))
Value after divison 4

scala> showResult(divide(16, 0))
Error: Denominator can not be zero

Can we make it more concise and expressive? Yes, we can give a try applying fold to it. Let’s see.

scala> def showResult(result: Either[String, Int]) =
     | result.fold(
     | error => s"Error: $error",
     | result => s"Division succeeded: $result"
     | )
showResult: (result: Either[String,Int])String

scala> showResult(divide(51, 17))
res21: String = Division succeeded: 3

scala> showResult(divide(51, 0))
res22: String = Error: Denominator can not be zero

We have seen how we can handle exceptions using Either and how we can get values from Either. We will explore more about Either in future blogs. Till then stay tuned 🙂

Please feel free to suggest and comment.

References:

  1. Daily Scala: Either
  2. Try, Option or Either?

knoldus-advt-sticker


2 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.