Why does this compile:
scala> def last[A](a : List[A] ) : A =
| a match {
| case head :: Nil => Some(head) get
| case _ :: tail => last(tail)
| case Nil => None get
| }
last: [A](a: List[A])A
While this obviously doesn’t:
scala> None get
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:262)
at .<init>(<console>:6)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:9)
at RequestResult$.<clinit>(<console>)
at RequestResult$scala_repl_result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
at scala.util.control.Exception$C...
The latter code does compile and fails just at runtime – what you see is an exception, not a compiler error.
Noneinherits fromOptionand thus must define the methodget.EDIT:
The question could be rephrased as “why does the compiler accept a clearly stupid call to
None.get?”. This question is indeed nontrivial to answer, so I’ll spend a few more words on it at different levels.Still, the savvy user will learn to recognize the different format of the errors.
getstupid, since it can fail at runtime? Indeed, when you have a valuevof typeOption[T], you should usually pattern match on it or use methods likegetOrElse,map, and so on: methods which work even ifvis empty. But sometimes you have such a value and are already sure thatvmust beSome(q): get should only be used then.The compiler gives an error when you call a method which is not defined on the receiver object, but
getis defined on theOptionclass, and therefore on its two subclasses,SomeandNone. It is only its body that contains a call to error.Optionmake sense? For the user to be call to callgetwhen he wants to, it must be defined onOption. Otherwise one would need a typecast before being able to call it – at that point, it’d be easier to just do pattern matching.Because recognizing the nontrivial cases is hard. For instance, in the function you posted above, it is not clear that
None.getis ever going to be executed; moreover, the code you gave will give a run-time error if you pass in an empty list; therefore it is a correct implementation of the usual specification of last. In general, you might havev getand it might be nontrivial to understand whethervmight or might not beNone. There are other tools which try to find this kind of bugs (not sure if any for Scala yet), but they also tend to give either false negatives or false positives: they might report problems which cannot happen, or miss relevant problems. In the end, you really don’t want their output to be together the output of the Scala compiler.Having some basic easy checks within the compiler might make sense, but there you have an engineering question: it’s not clear if the extra code is worth its cost.