Reputation: 1895
Take the simple function:
def makeUpper(input: Option[String]): String =
input.fold("b"){ _.toUpperCase }
makeUpper(Some("a")) // A
makeUpper(None) // b
This is as expected.
Now, the same code, but outside the function:
Some("a").fold("b"){ _.toUpperCase } // A
None.fold("b"){ _.toUpperCase } // error: value toUpperCase is not a member of Nothing
Note:
Option.empty[String].fold("b"){ _.toUpperCase } // b
Questions:
Is the function casting the input None to a "definitive" Option.empty[String]?
What am I missing?
Upvotes: 1
Views: 187
Reputation: 13985
Scala compiler can infer types.
Since you have defined the function parameter input
as Option[String]
, even if you pass None
, the compiler knows that it is an Option[String]
and appropritately types it.
Which is kind of doing this,
val none: Option[String] = None
none.fold("b"){ _.toUpperCase }
Or this,
(None: Option[String]).fold("b"){ _.toUpperCase }
When directly using None
without any extra information, the compiler still tries to infer best guess useing only available information which is None extends Option[Nothing]
and hence treats it as Option[Nothing]
. Which is equivalent to,
val none: Option[Nothing] = None
none.fold("b"){ _.toUpperCase }
or this,
(None: Option[Nothing]).fold("b"){ _.toUpperCase }
Notice that there is no indication of any relation to String
in this case.
As long as you help the compiler by telling your intended type even at one place. It will be able to infer intended types for other relatable places.
scala> val noneIntOpt = noneStringOpt
// val noneIntOpt: Option[String] = None
scala> val noneIntOpt = noneStringOpt.map(_.length)
// val noneIntOpt: Option[Int] = None
Upvotes: 3
Reputation: 27356
None
is defined as:
case object None extends Option[Nothing]
So when you call a method on the "contents" of None
you are calling a method on a value of type Nothing
. This type does not have a method toUpperCase
so you get an error.
However Nothing
is compatible with every type, and Option
is covariant with its type parameter, so Option[Nothing]
is compatible with Option[String]
. This is why None
can be passed to your makeUpper
method. Once the type of the contents is known to be String
the toUpperCase
method can be called on it.
Upvotes: 3