Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala.Either getOrElse method

Tags:

scala

either

Why when I type this all works fine?

Right(2).left getOrElse Right(4).left getOrElse Left("Error")

but when I type this compilation fails?

Right[String, Int](2).left getOrElse Right[String, Int](4).left getOrElse Left[String, Int]("Error")

Compilation error:

value getOrElse is not a member of java.io.Serializable
println(RightString, Int.left getOrElse RightString, Int.left getOrElse LeftString, Int)

So I can't chain getOrElse method call

like image 675
WelcomeTo Avatar asked Aug 21 '13 20:08

WelcomeTo


1 Answers

The signature of getOrElse for a LeftProjection[A, B] is:

def getOrElse[AA >: A](or: ⇒ AA): AA

i.e. it expects the argument to be of some type AA which is a supertype of A.

In the first example, you left out type annotations, allowing the compiler to infer Nothing for A. Then, you supplied an argument of type LeftProjection[Nothing, Int].

Because Nothing is a subtype of all types, LeftProjection[Nothing, Int] is trivially a supertype! This special case in the type system means that it type-checked almost by accident.

However, the most specific common supertype of String and LeftProjection[String, Int] is Serializable.


So, if you want to chain Eithers, you need a method which can take another Either[A, B], not just an A or B.

The method you seem to want would look like this:

def leftOrElse[A, B](e1: Either[A, B], e2: => Either[A, B]): Either[A,B] =
  e1 match {
    case Left(a) => Left(a)
    case Right(b) => e2
  }

(You could similarly write rightOrElse, which is a more common use case.)

This becomes syntactically a bit more usable if you make it an extension method, using implicits.

implicit class EitherOps[A, B](e1: Either[A, B]) {
  def leftOrElse(e2: => Either[A, B]): Either[A,B] = // as above
}

Because this expects Either[A, B] for both operands, instead of A or B (or some supertype thereof), you can chain your Eithers.

scala> Right[String, Int](2) leftOrElse Right[String, Int](4) leftOrElse Left[String, Int]("Error")
res1: Either[String,Int] = Left(Error)
like image 54
Ben James Avatar answered Oct 15 '22 04:10

Ben James