I am not able to understand the point of Option[T]
class in Scala. I mean, I am not able to see any advanages of None
over null
.
For example, consider the code:
object Main{
class Person(name: String, var age: int){
def display = println(name+" "+age)
}
def getPerson1: Person = {
// returns a Person instance or null
}
def getPerson2: Option[Person] = {
// returns either Some[Person] or None
}
def main(argv: Array[String]): Unit = {
val p = getPerson1
if (p!=null) p.display
getPerson2 match{
case Some(person) => person.display
case None => /* Do nothing */
}
}
}
Now suppose, the method getPerson1
returns null
, then the call made to display
on first line of main
is bound to fail with NPE
. Similarly if getPerson2
returns None
, the display
call will again fail with some similar error.
If so, then why does Scala complicate things by introducing a new value wrapper (Option[T]
) instead of following a simple approach used in Java?
UPDATE:
I have edited my code as per @Mitch's suggestion. I am still not able to see any particular advantage of Option[T]
. I have to test for the exceptional null
or None
in both cases. :(
If I have understood correctly from @Michael's reply, is the only advantage of Option[T]
is that it explicitly tells the programmer that this method could return None? Is this the only reason behind this design choice?
You'll get the point of Option
better if you force yourself to never, ever, use get
. That's because get
is the equivalent of "ok, send me back to null-land".
So, take that example of yours. How would you call display
without using get
? Here are some alternatives:
getPerson2 foreach (_.display)
for (person <- getPerson2) person.display
getPerson2 match {
case Some(person) => person.display
case _ =>
}
getPerson2.getOrElse(Person("Unknown", 0)).display
None of this alternatives will let you call display
on something that does not exist.
As for why get
exists, Scala doesn't tell you how your code should be written. It may gently prod you, but if you want to fall back to no safety net, it's your choice.
You nailed it here:
is the only advantage of Option[T] is that it explicitly tells the programmer that this method could return None?
Except for the "only". But let me restate that in another way: the main advantage of Option[T]
over T
is type safety. It ensures you won't be sending a T
method to an object that may not exist, as the compiler won't let you.
You said you have to test for nullability in both cases, but if you forget -- or don't know -- you have to check for null, will the compiler tell you? Or will your users?
Of course, because of its interoperability with Java, Scala allows nulls just as Java does. So if you use Java libraries, if you use badly written Scala libraries, or if you use badly written personal Scala libraries, you'll still have to deal with null pointers.
Other two important advantages of Option
I can think of are:
Documentation: a method type signature will tell you whether an object is always returned or not.
Monadic composability.
The latter one takes much longer to fully appreciate, and it's not well suited to simple examples, as it only shows its strength on complex code. So, I'll give an example below, but I'm well aware it will hardly mean anything except for the people who get it already.
for {
person <- getUsers
email <- person.getEmail // Assuming getEmail returns Option[String]
} yield (person, email)