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
?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With