## Accelerators

### Go to Overview

KDP KDSP

#### Products

PremonR CodeSquad Studio9

#### TechHub

Akka Scala Rust Spark Functional Java Kafka Flink ML/AI DevOps Data Warehouse

## Insights # Scala Cats: EitherT

Reading Time: 2 minutes

In this blog, I will discuss about EitherT which is another concept of Scala Cats library.

Before discussing about EitherT, lets discuss Either first then EitherT which helps us in resolving the issue or boilerplate we have due to Either.

## Either

`Either` can be used for error handling in most situations. However, when `Either` is placed into effectful types such as `Option` or `Future`, a large amount of boilerplate is required to handle errors

``````import scala.util.Try
import cats.implicits._

def parseDouble(s: String): Either[String, Double] =
Try(s.toDouble).map(Right(_)).getOrElse(Left(s"\$s is not a number"))

def divide(a: Double, b: Double): Either[String, Double] =
Either.cond(b != 0, a / b, "Cannot divide by zero")

def divisionProgram(inputA: String, inputB: String): Either[String, Double] =
for {
a <- parseDouble(inputA)
b <- parseDouble(inputB)
result <- divide(a, b)
} yield result

divisionProgram("4", "2") // Right(2.0)
// res0: Either[String, Double] = Right(2.0) // Right(2.0)
divisionProgram("a", "b") // Left("a is not a number")
// res1: Either[String, Double] = Left("a is not a number")``````

If both the methods are written in asynchronous way which may return Future[Either[String, Double]] then for-comprehension can not be used. So let’s see what else we can change in above code to make it appropriate according to the requirement.

``````import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

def parseDoubleAsync(s: String): Future[Either[String, Double]] =
Future.successful(parseDouble(s))
def divideAsync(a: Double, b: Double): Future[Either[String, Double]] =
Future.successful(divide(a, b))

def divisionProgramAsync(inputA: String, inputB: String): Future[Either[String, Double]] =
parseDoubleAsync(inputA) flatMap { eitherA =>
parseDoubleAsync(inputB) flatMap { eitherB =>
(eitherA, eitherB) match {
case (Right(a), Right(b)) => divideAsync(a, b)
case (Left(err), _) => Future.successful(Left(err))
case (_, Left(err)) => Future.successful(Left(err))
}
}
}``````

## EitherT

`EitherT[F[_], A, B]` is a lightweight wrapper for `F[Either[A, B]]` that makes it easy to compose `Either`‘s and `F`‘s together. To use `EitherT`, values of `Either``F``A`, and `B` are first converted into `EitherT`, and the resulting `EitherT` values are then composed using combinators

``````import cats.data.EitherT
import cats.implicits._

def divisionProgramAsync(inputA: String, inputB: String): EitherT[Future, String, Double] =
for {
a <- EitherT(parseDoubleAsync(inputA))
b <- EitherT(parseDoubleAsync(inputB))
result <- EitherT(divideAsync(a, b))
} yield result

divisionProgramAsync("4", "2").value
// res2: Future[Either[String, Double]] = Future(Success(Right(2.0)))
divisionProgramAsync("a", "b").value
// res3: Future[Either[String, Double]] = Future(Success(Left(a is not a number)))``````

There are different ways we can modify our methods so that it might return the value in different way. So lets just explore few such ways.

## From `A` or `B` to `EitherT[F, A, B]`

``````val number: EitherT[Option, String, Int] = EitherT.rightT(5)
val error: EitherT[Option, String, Int] = EitherT.leftT("Not a number")``````

## From `F[A]` or `F[B]` to `EitherT[F, A, B]`

``````val numberO: Option[Int] = Some(5)
val errorO: Option[String] = Some("Not a number")

val number: EitherT[Option, String, Int] = EitherT.right(numberO)
val error: EitherT[Option, String, Int] = EitherT.left(errorO)``````

## Extracting an `F[Either[A, B]]` from an `EitherT[F, A, B]`

``````val errorT: EitherT[Future, String, Int] = EitherT.leftT("foo")
// errorT: EitherT[Future, String, Int] = EitherT(Future(Success(Left(foo))))

val error: Future[Either[String, Int]] = errorT.value
// error: Future[Either[String, Int]] = Future(Success(Left(foo)))``````

Hope this blog will help you. I am also new to this concept so have taken a reference from documentation to get a better understanding about this concept.

Happy Blogging!

References:-  #### Written by Sanjana Aggarwal

Sanjana Aggarwal is a Software Consultant at Knoldus Software LLP, having experience of more than 1.5 years. She has done MCA from Bharati Vidyapeeth Institute of Computer Application and Management, Paschim Vihar. She has a decent knowledge of Java, Scala, Lagom, Kafka, Cassandra, Cocuhbase, MongoDB, Akka and Akka HTTP. She loves reading books and cooking and traveling.