Question

What is idiomatic way to work with Either's in Scala? For example when using Option I can use orElse method to get next optional value if current is None. But how to work with Either in same way? I didn't find method like orElse to chain Either's (and I understand that it's not good idea to have such method because we lost the Left value)

Edit: In fact I have a sequence of if-elseif-elseif-else expressions each returning Right or Left. And I want to refactor my code so it become "more functional". So I can replace it with firstOption orElse secondOption orElse... if it were Option, but how to use here Either?

Was it helpful?

Solution

Well there has been a very long discussion on this. Currently as you said Either is unbiased (i.e. Left and Right are treated as same). Hence one does not know what to do if orElse is called? Making it Right biased would had solved the problem (As Tony Morris puts it, it was a mistake)

So some hacks are: Using LeftProjection or RightProjection. Right Projection has utility functions map, flatMap, filter etc)

val a:Either[String, Int]
val b:Either[String, Int]

for{
x <- a.right //returns a RightProjection of a
y <- b.right
} yield (a,b)

Or a.right.getOrElse(b.right). One more solution would be as suggested here:

object Implicits {
    implicit def rightBiasEither[A, B](e: Either[A, B]): Either.RightProjection[A, B] = e.right
  }

import Implicits._
a.getOrElse(b).getOrElse(c)

This way you can keep using it as monad.


Update:

Post Scala 2.12, Either is right-biased, which means that Right is assumed to be the default case to operate on. If it is Left, operations like map and flatMap return the Left value unchanged:

 def doubled(i: Int) = i * 2
 Right(42).map(doubled) // Right(84)
 Left(42).map(doubled)  // Left(42)

You can read more on the Either API.

OTHER TIPS

Starting Scala 2.13, Either#orElse has been made available, (after Either being made right-biased in Scala 2.12):

Right(1) orElse Left(2) // Right(1)
Left(1) orElse Left(2)  // Left(2)
Left(1) orElse Left(2) orElse Right(3) // Right(3)

the most closest :

Left(1).left.flatMap(_=>Left(2)).left.flatMap(_=>Left(3))
res22: Either[Int, Nothing] = Left(3)

Right(1).left.flatMap(_=>Left(2)).left.flatMap(_=>Left(3))
res23: Either[Int, Int] = Right(1)

Use Try if you are dealing with Throwable:

either1.toTry orElse either2.toTry

Yes , in my opinion , the lack of orElse is inconsistency since Either now at 2.12 is right-biased and there's getOrElse method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top