Option, Some, and None

Question Click to View Answer

What does the following code print?

val x: Option[String] = Some("hi")
println(x.get)

"hi" is printed.

The x variable is typed as an Option[String] and assigned to the value Some("hi"). x.get fetches the String "hi".

What does the following code print?

var y: Option[String] = None
y.get

This code throws a java.util.NoSuchElementException: None.get exception.

y.get cannot return a String value, so it throws an exception.

None is a Scala object that represents nothingness and is generally preferred to using null directly.

What does the following code print?

val firstName: Option[String] = Some("Frank")
println(firstName.getOrElse("Sue"))

"Frank" is printed.

The getOrElse method will return a String if it's defined and return the default value otherwise.

What does the following code print?

val bestNumber: Option[Int] = None
println(bestNumber.getOrElse(8))

8 is printed.

The bestNumber variable is assigned to None, so getOrElse cannot fetch an integer and falls back to the default value of 8.

What does the following code print?

var myMood: Option[String] = Some("happy")
myMood = Some(10)
println(myMood.get)

This throws a type mismatch error.

myMood must be assigned to an Option[String] and cannot be assigned to an Option[Int].

What does the following code print?

val something = null
def getLength(x: String): Int = x.length
println(getLength(something))

This code returns a java.lang.NullPointerException.

This code ends up calling null.length which isn't a valid operation.

The Scala Some / Option / None classes exist so you can avoid NullPointerExceptions in your code.

null should be avoided in Scala code. You should never set a variable to null.

What does the following code print?

val something = null

def crappyGetLength(x: String): Any =
  if (x != null) x.length else null

println(crappyGetLength(something))

This code prints null.

The crappyGetLength function is terrible. You should never explicitly reference null in a Scala function. This function is a huge Scala anti-pattern.

Some, Option, and None exist so you can avoid writing code that directly references null.

What does the following code print?

def betterGetLength(x: Option[String]): Option[Int] =
  if (x.isDefined) Some(x.get.length) else None

println(betterGetLength(None))
println(betterGetLength(Some("puppy")))

betterGetLength(None) returns None

betterGetLength(Some("puppy")) returns Some(5).

This is better than using null directly, but it's not idiomatic Scala code. Avoid writing code like this.

What does the following code print?

def goodGetLength(x: Option[String]): Option[Int] =
  x.map(_.length)

println(goodGetLength(None))
println(goodGetLength(Some("puppy")))

goodGetLength(None) returns None

goodGetLength(Some("puppy")) returns Some(5).

This is an idiomatic way to deal with optional values in Scala.

You're probably used to seeing the map method when iterating over lists, so it's weird to see map being used for optional values.

Think of optional values as lists that can contain one or no values. Think of it like iterating over an empty list or iterating over a list that contains one value. When you think of optional values like lists that contain zero or one element, the map syntax makes more sense.

Let's write some code that'll create a collection of dogs, will fetch one of the dogs, and will print an attribute of the dog.

What does the following code print?

case class Dog(
  id: Int,
  firstName: String,
  nickName: Option[String])

val dog1 = Dog(1, "Spot", Some("foofie"))
val dog2 = Dog(2, "Luna", None)

val dogs = Map(
  1 -> dog1,
  2 -> dog2)

def findById(dogs: Map[Int, Dog], id: Int): Option[Dog] =
  dogs.get(id)

val d1 = findById(dogs, 1)
println(d1.map(_.nickName))

Some(Some("foofie")) is printed.

d1 is assigned to Some(Dog(1, "Spot", Some("foofie"))) and dog1.nickName is assigned to Some("foofie"), so d1.map returns a nested Some() value.

You don't typically want to write code that returns nested Some values.

How can you finish this code to return Some("foofie")?

case class Dog(
                id: Int,
                firstName: String,
                nickName: Option[String])

val dog1 = Dog(1, "Spot", Some("foofie"))
val dog2 = Dog(2, "Luna", None)

val dogs = Map(
  1 -> dog1,
  2 -> dog2)

def findById(dogs: Map[Int, Dog], id: Int): Option[Dog] =
  dogs.get(id)

val d1 = findById(dogs, 1)

d1.flatMap(_.nickName) will return Some("foofie").

Notice that we're using flatMap instead of map. The flatMap method is designed to avoid returning nested values.

What does the following code print?

case class Cat(name: String, age: Int)
val darla = Some(Cat("darla", 12))
println(darla.filter(_.age > 10))

Some(Cat("darla", 12)) is printed.

You can filter optional values. Scala returns the value if the predicate is true. In this case, the age > 10 predicate is true.

What does the following code print?

case class Cat(name: String, age: Int)
val chunkers = Some(Cat("chunkers", 4))
println(chunkers.filter(_.age > 10))

None is printed.

When you filter over an optional values and the predicate evaluates to false, Scala returns None.

What does the following code print?

case class Cat(name: String, age: Int)
val nala: Option[Cat] = None
println(nala.filter(_.age > 10))

None is printed.

The filter method does not blow up when it filters over a None value. It gracefully returns None.

You should start to be seeing how Scala's option handling methods like filter help you sidestep the NullPointerException errors you'd be facing if you were using null directly in your code.

Why should null be avoided in Scala?

The Scala community discourages using null because it helps you avoid null pointer exceptions and encourages a safer type of functional programming. See Alvin Alexander's full writeup here.