10

Why is the method get defined in Option and not in Some?

One could apply pattern matching or use foreach, map, flatMap, getOrElse which is preferred anyway without the danger of runtime exceptions if None.get is called.

Are there really cases where the get method is so much convinent that it justifies this? Using the get method reminds me to Java where "I don't have to check for null because I know the var is set" and then see a NullPointerException.

Manuel Schmidt
  • 2,429
  • 1
  • 19
  • 32
  • 2
    I guess it is for migration from `Java`. Sometimes it's useful in `REPL`. I'd like to have a compiler option to treat `.get` as error. – senia May 21 '13 at 05:11
  • 3
    In the same vein: why is there a List.head method? Interestingly, even Haskell has it, resulting in a runtime error when applied to an empty list. – Régis Jean-Gilles May 21 '13 at 06:44
  • 2
    To get even closer to the core of the question: why are there exceptions (or other things that make a function partial)? –  May 21 '13 at 08:14
  • 1
    Did anyone mention https://issues.scala-lang.org/browse/SI-7262? – som-snytt May 22 '13 at 00:02

5 Answers5

6

Option.get is occasionally useful when you know, by reasoning that isn't captured by the type system, that the value you have is not None. However, you should reach for it only when you've tried:

  • Arranging for this knowledge to be expressed by your types.
  • Using the Option processing methods mentioned (flatMap, getOrElse etc), and none of them fit elegantly.

It's also convenient for throwaway / interactive code (REPL, worksheets etc).

Matt R
  • 9,892
  • 10
  • 50
  • 83
  • 4
    That's pretty much it. I do think the syntactic overhead for doing this should be higher to be less tempting to newbies who think "dammit, my value is in an `Option`! how can I get it out?! oh, `get`" – Mysterious Dan May 21 '13 at 14:01
  • @MyseriousDan - maybe, although it's also the sort of thing you can easily flag up with static analysis tools. – Matt R May 21 '13 at 16:26
  • Sure, but code analysis is a retrospective tool. My goal is to make developers feel guilty about using it in the first place, so that they design their code not to need it. A three-letter word with no guilt-inspiring words in it like `unsafeGet` or `getButThisWillLeadToBugsIPromise` is not a sufficient deterrent, in my opinion. Detecting it doesn't help much if you find 1500 instances of it in your codebase and rearchitecting it to push those errors toward the user will take 5 man-years of work. – Mysterious Dan May 21 '13 at 17:15
  • @MyseriousDan well, the downside is that a 30 character name is to the detriment of the legitimate uses -- not sure that's a good trade. My suggestion would be to pick up bad style in regular code peer review sessions -- devs new to Scala will need this anyway, in my experience. – Matt R May 22 '13 at 11:26
  • 1
    My point is that the illegitimate uses vastly outnumber the legitimate ones and we should not optimize for the occasional latter case. Someone using `get` needs to feel a pang of guilt when using it to make sure it's really necessary and can't be done more cleanly. – Mysterious Dan May 22 '13 at 13:22
  • I agree with MyseriousDan. And IMHO if you can guarantee that the variable is not None, then you should not use `Option` in the first place. If you get the Option from some other function then you (most likely) cannot guarantee that it is not a None (or will change in future implementation) – Manuel Schmidt May 24 '13 at 05:11
  • 1
    @ManuelSchmidt: I agree in general, just that there are a minority of occasions when `get` is still reasonable. I recently wrote some code to return Some(topological sort) of a directed graph, if it had one, else None. Also, some code to break cycles in an arbitrary graph and return an acyclic graph. A third routine ran the cycle-breaking code, then obtained a topological sort. Calling `get` on the result is reasonable, because we can prove that it is safe -- even though the types don't capture that property. (You could represent that in types, but I think it would be overkill here). – Matt R May 24 '13 at 09:57
2

Foreword

Scala was created with compatibility for the JVM as a target.

So it's pretty natural that Exceptions and try/catch should be considered as part of the language, at least for java interoperability.

With this premise in mind, now to the point of including interfaces that can throw errors in algebraic data types (or case classes if you prefer).


To the Question

Assume we encapsulate the get method (or head for List) only in Some instance.
This implies that we're forced to pattern match on the Option every time we want to extract the value. It wouldn't look pretty neat, but it's still a possibility.

We could getOrElse everywhere but this means that I can't signal a failure through the error stack if using imperative style (which is not forbidden in scala, the last time I checked).

My point here is that getOrElse and headOption are available to enforce a functional style when desired, but get and head are good alternatives if imperative is a choice fit to the problem or the programmer's preference.

pagoda_5b
  • 7,333
  • 1
  • 27
  • 40
  • 1
    I don't agree that get and head imply imperative programming, or that getOrElse/HeadOption imply functional programming. That's like saying `if` is not allowed in functional programming, but that simply doesn't follow. – Rick-777 May 21 '13 at 17:51
  • `if` doesn't return any value, as opposed to `if/else`, so I would assume it's not purely functional, but an imperative control flow element. But I'm not considering too deeply the implications here. – pagoda_5b May 21 '13 at 20:29
0

There is no good reason for it. Martin Odersky added it in this commit in 2007, so I guess we'd need to ask him his motivations. The earlier version had getOrElse semantics.

Jed Wesley-Smith
  • 4,686
  • 18
  • 20
  • Martin Odersky didn't add `get` method in this commit. There was already method [`get: A`](https://github.com/scala/scala/commit/cc4427befb91bcdc183008d8a0cc727f0549f55e#L1L43). He moved an implementation from `Option` to `Some` and `None`. – senia May 21 '13 at 08:45
  • 2
    Method `get` is in `Option` since [initial version](https://github.com/scala/scala/blob/23d2bfbeb21f63d82ed46d5b1b0b85b1ed2f4355/sources/scala/Option.scala). – senia May 21 '13 at 08:55
  • ...which does not mean much. `getOrElse` could as well be abstract and independently implemented in `Some` and `None`, or left as is (minus the @inline) and have `get` as a private method. – Régis Jean-Gilles May 21 '13 at 10:05
0

If you examine the commit provided. It's kind of obvious why and when it is used. The get is used to unbox when you are sure there is Something in the Option. It would also serve to be an inheritable method where None.get Throws an exception and Some.get unboxes the contents.

korefn
  • 955
  • 6
  • 17
0

In some cases, when your Option turns out to be a None, there is no recourse and you want to throw an exception. So, instead of writing

myOption match {
  case Some(value) => // use value
  case None => throw new RuntimeException("I really needed that value")
}

you can simply write

myOption.get // might throw an exception

It also makes Option much nicer to use from Java, in conjunction with isDefined:

if (myOption.isDefined()) process(myOption.get());
else // it's a None!
Connor Doyle
  • 1,812
  • 14
  • 22
  • A agree it's nicer from Java. However I don't agree with your first argument. If you need to throw an exception then it should be explicit in the code and the exception should have a meaningful message and no the default returned by `Option.get` – Manuel Schmidt May 24 '13 at 05:05
  • Could go either way. Often you'll see a chunk of code where a number of exceptions may be thrown only to be caught and wrapped something context-aware higher up the call stack. Nonetheless, let's not engage in holy wars over exception handling here :) – Connor Doyle May 24 '13 at 21:33