26

Besides using match, is there an Option-like way to getOrElse the actual content of the Right or Left value?

scala> val x: Either[String,Int] = Right(5)
scala> val a: String = x match { 
                                case Right(x) => x.toString
                                case Left(x) => "left" 
                       }
a: String = 5
Kevin Meredith
  • 38,251
  • 58
  • 190
  • 340

4 Answers4

18

I don't particularly like Either and as a result I'm not terribly familiar with it, but I believe you're looking for projections: either.left.getOrElse or either.right.getOrElse.

Note that projections can be used in for-comprehensions as well. This is an example straight from the documentation:

def interactWithDB(x: Query): Either[Exception, Result] =
  try {
    Right(getResultFromDatabase(x))
  } catch {
    case ex => Left(ex)
  }

// this will only be executed if interactWithDB returns a Right
val report =
  for (r <- interactWithDB(someQuery).right) yield generateReport(r)
if (report.isRight)
  send(report)
else
  log("report not generated, reason was " + report.left.get)
Nicolas Rinaudo
  • 5,712
  • 25
  • 40
  • 5
    Why don't you like `Either`? – Kevin Meredith Oct 21 '13 at 21:24
  • 8
    @Kevin this is my personal opinion only, but I find that there are two cases where it's useful: to return a failure or success, or to return one of two possible results. The former is better served by using a `Try` and the latter just seems like sloppy programming - I feel that if my method can return either a `String` or a `Date`, for example, it could do with some refactoring. – Nicolas Rinaudo Oct 21 '13 at 21:31
  • 2
    I think it's useful in a validation framework to return a success or failure. The public API would then explicitly tells you which kind of success/failure it can return, even when they're custom statefull classes, while avoiding the awkward use of checked exceptions. An example I'm currently working on is an event-sourcing framework, that will dispatch an event based on some validation. It could be either the expected type of event, or some kind of "Invalid event" – Guillaume Oct 22 '13 at 14:36
  • 1
    @Guillaume I feel it *was* a useful device, until 2.10's [Try](http://www.scala-lang.org/api/current/index.html#scala.util.Try) made it obsolete for that purpose. `Try` can be considered an `Either` that doesn't rely on convention (do failures go the `Left` or the `Right`?) and can be written in a way that's very smoothly reminiscent of old fashioned `try/catch` blocks. I'd be happy to have a more in depth conversation on the topic, but maybe we should move that conversation to its own question, maybe on [Programmers](http://programmers.stackexchange.com)? – Nicolas Rinaudo Oct 22 '13 at 14:45
  • Ah I thought you were talking about try (as in try/catch). I confess I had never heard of Try although I'm using 2.10, will definitely have a look, thanks :) – Guillaume Oct 22 '13 at 14:47
  • 3
    For Try, what if you have behavior that is **wrong** but not exceptional? Is that still a good candidate for Try? Maybe it could be exceptional, but I try to write code without exceptions necessary. – Kevin Meredith Oct 23 '13 at 03:08
  • 1
    If something went wrong but not exceptionally so (that is, you don't have a result but neither do you have an `Exception` to wrap), I like to use `Option` - an instance of `None` is essentially a non-`null` way of telling callers that you cannot honour their request without throwing an `Exception`. – Nicolas Rinaudo Oct 23 '13 at 06:56
  • 2
    @Nicolas Rinaudo, @ Nicolas Rinaudo, What if you want to tell client that function may return several types of errors, for example InvalidDataError and InetrnalError, how would you do it with Try? With Either, you may write like this : def method(input: Int):Either[(Option[InvalidDataError], Option[InternalError]), Int] - and client of that method nows what kind of error may occur, and handle them if he wants. How would you do this with Try? – Teimuraz Aug 13 '16 at 19:49
16

Nicolas Rinaudo's answer regarding calling getOrElse on either the left or right projection is probably the closest to Option.getOrElse.

Alternatively, you can fold the either:

scala> val x: Either[String,Int] = Right(5)
x: Either[String,Int] = Right(5)

scala> val a: String = x.fold(l => "left", r => r.toString)
a: String = 5

As l is not used in the above fold, you could also write x.fold(_ => "left", r => r.toString)

Edit: Actually, you can literally have Option.getOrElse by calling toOption on the left or right projection of the either, eg,

scala> val o: Option[Int] = x.right.toOption
o: Option[Int] = Some(5)

scala> val a: String = o.map(_.toString).getOrElse("left")
a: String = 5
Kristian Domagala
  • 3,548
  • 17
  • 22
3

Given type A on both sides, that is, Either[A, A], we can use Either.merge

...to extract values from Either instances regardless of whether they are Left or Right.

Note if left and right types differ then result becomes Any:

val e: Either[Int, String] = Right("hello")
e.merge // hello: Any
Mario Galic
  • 41,266
  • 6
  • 39
  • 76
1

In Scala 2.12 there is a getOrElse method for getting the "right" value but you cannot use it for the "left" value directly. However, you can do it like this: e.swap.getOrElse(42).

lex82
  • 10,346
  • 2
  • 37
  • 63
  • I don't think that having 'any' as a type is something what worth it. Feels like you breaking type system – Stanislav Sobolev Dec 28 '19 at 01:28
  • @StanislavSobolev what do you mean? There should be no loss of type information. Swapping the `Either` just gives you a new `Either` with swapped types. – lex82 Dec 28 '19 at 19:19