Manipulating instances of Option

The following is a simplified definition of the Option ADT:

sealed trait Option[+A]
case class Some[A](value: A) extends Option[A]
case object None extends Option[Nothing]

The Scala SDK provides a more refined implementation; the preceding definition is just for illustrative purpose. This definition implies that Option can be either of the following two types:

  • Some(value), which represents an optional value where the value is present
  • None, which represents an optional value where the value is not present.
The + sign in front of the A type parameter in the Option[+A] declaration means that Option is covariant in A. We will explore contravariance in more details in Chapter 4Advanced Features.
For now, you just have to know that if B is a subtype of A, then Option[B] is a subtype of Option[A].
Furthermore, you might notice that None actually extends Option[Nothing] and not Option[A]. This is because a case object cannot accept a type parameter.
In Scala, Nothing is the bottom type, which means that it is a subtype of any other type. 
This implies that None is a subtype of Option[A] for any A.

The following are some examples of the usage of the different types of Option that you can paste in a Scala worksheet:

val opt0: Option[Int] = None
// opt0: Option[Int] = None

val opt1: Option[Int] = Some(1)
// opt1: Option[Int] = Some(1)

val list0 = List.empty[String]
list0.headOption
// res0: Option[String] = None
list0.lastOption
// res1: Option[String] = None

val list3 = List("Hello", "World")
list3.headOption
// res2: Option[String] = Some(Hello)
list3.lastOption
// res3: Option[String] = Some(World)

Explanation of the preceding code is as follows:

  • The first two examples show how we can define an Option type that can optionally contain Int.
  • The following examples use the headOption and lastOption methods in List to show that many safe functions of the SDK return Option. If List is empty, these functions always return None. Note that the SDK also provides unsafe equivalent head and last methods. The unsafe methods throw an exception if we call them with an empty List, which might crash our program if we do not catch the exception.
Many functions of the SDK provide equivalent safe (which return Option) and unsafe functions (which throw an exception). It is a best practice to always use the safe alternative.

Since Option is an ADT, we can use pattern matching to test whether Option is None or Some, as shown in the following code:

def personDescription(name: String, db: Map[String, Int]): String =
db.get(name) match {
case Some(age) => s"$name is $age years old"
case None => s"$name is not present in db"
}

val db = Map("John" -> 25, "Rob" -> 40)
personDescription("John", db)
// res4: String = John is 25 years old
personDescription("Michael", db)
// res5: String = Michael is not present in db

The get(key)method in Map returns Option, containing the value associated with the key. If the key does not exist in Map, it returns None. When you start using Option, pattern matching is the most natural way of triggering different behaviors depending on the content of Option.

Another way is to use map and getOrElse, as shown in the following code:

def personDesc(name: String, db: Map[String, Int]): String = {
val optString: Option[String] = db.get(name).map(age => s"$name is
$age years old")
optString.getOrElse(s"$name is not present in db")
}

We saw earlier how to transform the elements of a vector using map. This works exactly the same for Option—we pass an anonymous function that will be called with the option's value if Option is not empty. Since our anonymous function returns a string, we obtain Option[String]. We then call getOrElse, which provides a value in case Option is None. The getOrElse phrase is a good way to safely extract the content of Option.

Never use the .get method on Option—always use .getOrElse. The .get method throws an exception if Option is None, and hence is not safe.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset