Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of the class Option[T]?

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?

like image 865
missingfaktor Avatar asked Jan 16 '10 22:01

missingfaktor


People also ask

What is an option t?

Advertisements. Scala Option[ T ] is a container for zero or one element of a given type. An Option[T] can be either Some[T] or None object, which represents a missing value.

What is the use of option in scala?

The Option in Scala is referred to a carrier of single or no element for a stated type. When a method returns a value which can even be null then Option is utilized i.e, the method defined returns an instance of an Option, in place of returning a single object or a null.

What is some () in scala?

Scala some class returns some value if the object is not null, it is the child class of option. Basically, the option is a data structure which means it can return some value or None. The option has two cases with it, None and Some. We can use this with the collection.

What are options in Java?

Class Options. java.lang.Object org.apache.commons.cli.Options public class Options extends Object. Main entry-point into the library. Options represents a collection of Option objects, which describe the possible options for a command-line. It may flexibly parse long and short options, with or without values.


4 Answers

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) 
like image 170
Daniel C. Sobral Avatar answered Oct 04 '22 11:10

Daniel C. Sobral


Compare:

val p = getPerson1 // a potentially null Person val favouriteColour = if (p == null) p.favouriteColour else null 

with:

val p = getPerson2 // an Option[Person] val favouriteColour = p.map(_.favouriteColour) 

The monadic property bind, which appears in Scala as the map function, allows us to chain operations on objects without worrying about whether they are 'null' or not.

Take this simple example a little further. Say we wanted to find all the favourite colours of a list of people.

// list of (potentially null) Persons for (person <- listOfPeople) yield if (person == null) null else person.favouriteColour  // list of Options[Person] listOfPeople.map(_.map(_.favouriteColour)) listOfPeople.flatMap(_.map(_.favouriteColour)) // discards all None's 

Or perhaps we would like to find the name of a person's father's mother's sister:

// with potential nulls val father = if (person == null) null else person.father val mother = if (father == null) null else father.mother val sister = if (mother == null) null else mother.sister  // with options val fathersMothersSister = getPerson2.flatMap(_.father).flatMap(_.mother).flatMap(_.sister) 

I hope this sheds some light on how options can make life a little easier.

like image 33
Synesso Avatar answered Oct 04 '22 12:10

Synesso


The difference is subtle. Keep in mind to be truly a function it must return a value - null is not really considered to be a "normal return value" in that sense, more a bottom type/nothing.

But, in a practical sense, when you call a function that optionally returns something, you would do:

getPerson2 match {
   case Some(person) => //handle a person
   case None => //handle nothing 
}

Granted, you can do something similar with null - but this makes the semantics of calling getPerson2 obvious by virtue of the fact it returns Option[Person] (a nice practical thing, other than relying on someone reading the doc and getting an NPE because they don't read the doc).

I will try and dig up a functional programmer who can give a stricter answer than I can.

like image 24
Michael Neale Avatar answered Oct 04 '22 12:10

Michael Neale


For me options are really interesting when handled with for comprehension syntax. Taking synesso preceding example:

// with potential nulls
val father = if (person == null) null else person.father
val mother = if (father == null) null else father.mother
val sister = if (mother == null) null else mother.sister

// with options
val fathersMothersSister = for {
                                  father <- person.father
                                  mother <- father.mother
                                  sister <- mother.sister
                               } yield sister

If any of the assignation are None, the fathersMothersSister will be None but no NullPointerException will be raised. You can then safely pass fathersMothersSisterto a function taking Option parameters without worrying. so you don't check for null and you don't care of exceptions. Compare this to the java version presented in synesso example.

like image 20
paradigmatic Avatar answered Oct 04 '22 13:10

paradigmatic