8

I would like to initialize an Either to Left, but this requires specifying the type of the Right side (or vice versa).

If I don't, then the Right side is typed to Nothing by default, and in order to do something such as:

List(5, 42, 7).foldLeft(Left("empty")) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}
error: type mismatch;
    found   : scala.util.Right[Nothing,Int]
    required: scala.util.Left[String,Nothing]

I'm obviously forced to verbosely provide the type of both sides of the Either:

List(5, 42, 7).foldLeft(Left("empty"): Either[String, Int]) {
  case (Left(_), i)  => Right(i)
  case (Right(s), i) => Right(s + i)
}

In a similar way, I can use Option.empty[Int] to initialize None as an Option[Int], would there be a way to initialize Left("smthg") as an Either[String, Int]?

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190

2 Answers2

18

Starting Scala 2.13, Left comes with a Left#withRight method which allows upcasting Left[A, Nothing] to Either[A, B]:

Left("smthg").withRight[Int]
// Either[String, Int] = Left("smthg")
Left("smthg")
// Left[String, Nothing] = Left("smthg")

Same goes for the Right side and withLeft:

Right(42).withLeft[String]
// Either[String, Int] = Right(42)

which gives in your case:

List(5, 42, 7).foldLeft(Left("empty").withRight[Int]) {
  case (Left(_),  i) => Right(i)
  case (Right(s), i) => Right(s + i)
}
// Either[String, Int] = Right(54)
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
11

To supplement Xavier's answer, cats also provide utility methods for creating Either, for example, we can do:

import cats.implicits._

val right = 7.asRight[String] // Either[String, Int]

val left: = "hello cats".asLeft[Int] // Either[String, Int]

It might be useful if in case our project is using scala 2.12 or below.

In case we don't need whole cats library, we can, of course, borrow just extension functions for either:

implicit class EitherIdOps[A](private val obj: A) extends AnyVal {

  /** Wrap a value in `Left`. */
  def asLeft[B]: Either[A, B] = Left(obj)

  /** Wrap a value in `Right`. */
  def asRight[B]: Either[B, A] = Right(obj)

}
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76