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
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 Either
s, 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 Either
s.
scala> Right[String, Int](2) leftOrElse Right[String, Int](4) leftOrElse Left[String, Int]("Error")
res1: Either[String,Int] = Left(Error)
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