79

Given an Option, what is the idiomatic way to get its value or throw an exception trying?

def foo() : String = {
  val x : Option[String] = ...
  x.getOrException()
}
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 12
    Why not `.get`? – Mysterious Dan Apr 28 '13 at 17:47
  • @MyseriousDan I just stumbled upon this case. I have one situation where I'm absolutely 100% certain it must return Some, and if not, it's a serious problem and must throw. But I want to throw my own exception and any ambiguous `NoSuchElementException` ones. Also, most of the time this method may return None safely. – Kai Sellgren Mar 20 '14 at 18:18
  • 1
    The real question is why your type says it might be missing when you know that it isn't. If you can express your knowledge in types, that's generally best. It might involve reshaping your classes a bit, but will generally be a lot more pleasant in the long run. – Mysterious Dan Mar 24 '14 at 19:42
  • 1
    @TravisBrown 's answer should be the accepted one, not mine. Mine is not idiomatic, I wrote it when I still was a "newbie" (I still am, but level 2). Let it stand as an example what _not_ to do... ;-) – Sebastian N. Jan 18 '15 at 20:59
  • You are doing it wrong if you are having to throw an exception.The idiomatic way to use Option is to return None and not throw an exception at all. – Priyank Desai Mar 10 '16 at 19:58
  • I think there is a use case where throwing the exception is correct. I have a `Solver`, uses many `Variable` to create a `Solution`. To get a value, I want to call `solution.getValue(variable)`. `Solution` contains a map from `Variable` to the value in the solution, so `map.get(variable)` should always return `Some`. If it returns `None`, there is a bug in the code (either the `Solver` code or the user code) and nothing useful is going to happen. I can throw an exception, and include things like the variable name in the message now, or get a generic exception later. – Troy Daniels Jul 26 '18 at 15:16
  • Possible duplicate of [scala better syntax for map getOrElse](https://stackoverflow.com/questions/12504650/scala-better-syntax-for-map-getorelse) – Moha the almighty camel Aug 21 '18 at 10:05

6 Answers6

142

A throw "statement" is really an expression in Scala, and it has type Nothing, which is a subtype of every other type. This means you can just use plain old getOrElse:

def myGet[A](oa: Option[A]) = oa.getOrElse(throw new RuntimeException("Can't."))

You really, really shouldn't be doing this, though.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • 1
    Why not? What is a more elegant / idiomatic way of doing this? Pattern matching? – Sebastian N. Apr 29 '13 at 09:11
  • 7
    You get a lot more mileage out of the type system if you model failures as values all the way through your program (and save exceptions for truly exceptional problems—e.g. `OutOfMemoryError`). – Travis Brown Apr 29 '13 at 17:32
  • 25
    I don't see the advantage modeling failures as values for any unrecoverable problems (of which OOME is clearly one). Take for instance reading meta-data from a configuration file. Proper execution of the program requires a well-formed configuration file. If the configuration file contains invalid entries due to user error, then the program cannot continue. So it seems suitable to unroll the stack and back-out in such scenarios. – Coder Guy Dec 17 '14 at 03:09
  • 1
    @JonathanNeufeld The comment from Travis Brown sounds like a more fp purist approach. It is not for everyone /every use case. I'm more on your end - just bail and do not drive too much logic / fancy type system handling . – WestCoastProjects Sep 15 '17 at 22:26
  • I don't think @TravisBrown is a purist, his other answers on SO shows otherwise. However, throwing or modeling failure is indeed a question of context. In many cases, application failure is not an option (but for unrecoverable error such as OOME). If this is the case, failure management should be model throughout the code, and be traceable by design. – Juh_ Apr 25 '18 at 10:30
  • 1
    There are a lot of situations, e.g. in Akka when throwing is perfectly normal. There is nothing wrong with it. – Kirill G. Nov 21 '20 at 13:25
  • "You really, really shouldn't be doing this, though." This is completely misleading / waaay over the top. You might be checking user input and have a utility function that returns none if the input is invalid. The caller of that function might want to throw if it is none. – 5fec Feb 13 '22 at 02:32
  • I think the middle-ground is to use Either (with a value or Try object) and let the caller decide if it is a recoverable error. – TiN Jul 18 '23 at 20:05
51

(EDIT: this is not the best or most idiomatic way to do it. I wrote it when I was not familiar with Scala. I leave it here for an example of how not to do it. Nowadays I would do as @TravisBrown)

I think it really boils down to two things:

  • how sure are you that the value is there?
  • how do you want to react if it isn't?

If at that point in your code you expect the value to be there, and in the remote case that it isn't you want your program to fail fast, then I would only do a normal get and let Scala throw a NoSuchElementException if there was no value:

def foo() : String = {
  val x : Option[String] = ...
  x.get
}

If you want to handle the case differently (throw your own exception) I think a more elegant way would look like this:

def foo(): String = {
  val x: Option[String] = None
  x match {
    case Some(value) => value
    case None => throw new MyRuntimeException("blah")
  }
} 

And of course if you want to supply your own alternative value for the case that the Option is None you would just use getOrElse:

def foo(): String = {
  val x: Option[String] = None
  x.getOrElse("my alternative value")
} 
Sebastian N.
  • 1,962
  • 15
  • 26
  • Of course it should be noted that matching agains Some(value) just to extract that same value is not idiomatic Scala and that `getOrElse` should be preferred if that's all one wants to do. I just wanted to illustrate the case of "if defined, evaluate to X, if not, throw exception". – Sebastian N. Apr 30 '13 at 23:48
  • 1
    To [quote Guillaume Belrose](http://stackoverflow.com/questions/8559537/where-does-the-flatmap-that-s-idiomatic-expression-in-scala-come-from/8561903#comment10612358_8561903): "I guess I am still at the amateur hour then :-)" – Sebastian N. Apr 30 '13 at 23:51
  • 14
    You can also combine @SebastianN.'s suggestions by throwing an exception in `getOrElse` like so: `x.getOrElse(throw new MyRuntimeException("message"))` – Jona Jan 12 '15 at 20:00
  • 4
    @TravisBrown: after gaining more Scala experience I have to say you are right. Matching on Option like this instead of using getOrElse is unnecessary and not idiomatic. Yours should be the accepted answer. – Sebastian N. Jan 18 '15 at 21:01
14

I hope this will help you to understand how to represent errors (and generally effects) using types.

Error handling strategies in functional Scala

  • Use Option to return optional values. For example - fail to find entity in storage.

  • Use Option(possiblyNull) to avoid instances of Some(null).

  • Use Either[Error, T] to report expected failure. For example - email format is wrong, cannot parse a string to a number, etc.

  • Model your errors as ADTs (simply speaking kind of type hierarchies) to use it, for example, on the Left of the Either to represent more complex error scenarios.

  • Throw Exception only to signal unexpected and not-recoverable failures. Like missing config file.

  • Use Either.catchOnly or Try or Cats.IO (advanced) rather than a catch block for handling unexpected failures. Hint: You can still use ADT but extend them from throwables. More about Either vs Try.

  • Use Validated data-type from Cats lib to accumulate errors rather than fail-fast (Either), but prefer Either's on module-level to simplify the composition of the program (to have the same types). For example - form data validation, parsing errors accumulation.

  • Use mentioned types and don't optimize program preemptively - since most probably, bottle-necks would be in business logic, not in effect types.

Such an approach will simplify maintenance and updates of your code since you can reason about it without going to implementation specifics (aka local-reasoning). Also - reduce bugs - you cannot miss an error in the type. And compose the program easier (with help of map, flatMap and other combinators) - since it's simpler on type level, rather than with non-local exceptions and side-effects.
More about learning functional Scala.


But be aware that sometimes with this approach types could stack up and it could become harder to compose things. Given, for example: x: Future[Either[Error, Option[T]]] What you can do:

  • Use map and flatMap in combination with pattern-matching to compose different values of such types, for example:
x.faltMap { case Right(Some(v)) => anotherFuture(v); case Left(er) => ... }
  • If it doesn't help you can try to use MonadTransformers (don't be scared of the name, it's just wrappers around the effect types like Either and Future)
  • Also, an option is to simplify your errors ADT by extending them from the Throwable to unify it with Future, then it'll be Future[Option[T]]


And finally, in your case one option will be:

def foo() : Either[Error, String] = {
    val x : Option[String] = ...
    x match {
        case Some(v) => Right(v)
        case None => Left(Error(reason))
    }
}
Community
  • 1
  • 1
Albert Bikeev
  • 375
  • 6
  • 16
  • Pretty nice rundown. You left off the last "thought" in mid-sentence ;) – WestCoastProjects Sep 15 '17 at 22:28
  • @YordanGeorgiev link is rotten, removed – Albert Bikeev Oct 26 '17 at 12:37
  • This doesn't answer the question: "what is the idiomatic way to get its value or throw an exception trying?" I think perhaps you thought the OP was misguided and would benefit from some education; perhaps you were right. But there are times (for example due to invalid user input) when one wants to throw an exception if an option is none and this SO post is asking how to do it. As far as I can see your answer shows the OP how to model things but doesn't show them what the idiomatic way is to throw (with a custom error message) when it's none. – 5fec Feb 13 '22 at 02:27
13

Just use the .get method.

def get[T](o:Option[T]) = o.get

It will throw a NoSuchElementException if o is an instance of None.

Basically, I would work with options like this:

def addPrint(oi:Option[Int]) = oi.map(_+1).foreach(println)
addPrint(Some(41))
addPrint(Some(1336))
addPrint(None)

to avoid your specific question.

Felix
  • 8,385
  • 10
  • 40
  • 59
  • 4
    I was assuming the OP wanted more control over the exception thrown, but even if not, `get` is a bad idea—it just papers over the fact that you're doing something unpleasant. Using `getOrElse` and explicitly throwing an exception is harder to miss when you decide this isn't just one-off code and want to make it safer. – Travis Brown Apr 28 '13 at 14:10
  • Of course, basically it seems to me that you should _never_ use any kind of get on options unless you really really have to. I would use foreach or map to do computations with options. – Felix Apr 28 '13 at 16:15
2

Scala now support this operation on maps using getOrElse() method, see documentation here

As pointed out already, throwing an exception in Scala is an expression as well.

So you can do the following:

myMap.getOrElse(myKey, throw new MyCustomException("Custom Message HERE")
Moha the almighty camel
  • 4,327
  • 4
  • 30
  • 53
0

Since other answers suggest using tricky syntax constructs or using functional error handling, an extension method seems like a better fit:

object OptionExtensions {
  extension [T] (opt: Option[T]) {
    def getOrThrow(exception: () => Exception): T = {
      opt match
        case Some(value) =>
          value
        case None => 
          throw exception()
    }
  }
}

x.getOrThrow(() => Exception("Failed to get X"))
R A
  • 149
  • 1
  • 9