Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala.Either orElse method

Tags:

scala

either

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?

like image 707
WelcomeTo Avatar asked Aug 21 '13 08:08

WelcomeTo


3 Answers

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.

like image 124
Jatin Avatar answered Dec 08 '22 11:12

Jatin


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)
like image 22
Xavier Guihot Avatar answered Dec 08 '22 12:12

Xavier Guihot


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.

like image 23
WeiChing 林煒清 Avatar answered Dec 08 '22 11:12

WeiChing 林煒清