Option type, Some and None
The Option type is a very convenient way to avoid checking null pointers.
Here is a classical "null pointer checking" situation:
The getOrElse method calls the get method directly and matches the proper Option[B] pattern as shown in the previous example. The passed-in default function is invoked when the value associated with the key matches None (i.e. the key is not referenced within the map).
Here is a last example using the Map collection:
For more information, please have a look to this article from David Pollack about a concrete use of the Option type within the Lift framework.
Here is a classical "null pointer checking" situation:
def getString : String = {
...
"a string"
...
null
}
val str = getString
val str2 = if (str == null) "[null]" else str
This code can be replaced by the following one:
def getString : Option[String] = {
...
Some("a string")
...
None
}
val str = getString.getOrElse("[null]")
It's using the Option type together with the Some case class and the None object (from Option.scala):
sealed abstract class Option[+A] extends Product {
...
}
final case class Some[+A](x: A) extends Option[A] {
...
}
case object None extends Option[Nothing] {
...
}
The rules are very simple:
- replace your type T by Option[T]
- instead of returning myInstance (an intance of type T), return Some(myInstance) which is of type Option[T]
- instead of returning null, return None whose type is Option[Nothing] (the type Nothing being a subtype of every other type)
/** If the option is nonempty return its value, * otherwise return the result of evaluating a default expression. * * @param default the default expression. */ def getOrElse[B >: A](default: => B): B = ...Here is another example based on a list of Option[String]:
// allows using String when Option[String] is required
implicit def str2optStr(s:String):Option[String] = Some(s)
// list of strings
// attention: do not use 'null', use 'None' instead
val strings = List[Option[String]](Some("some string"), None, "raw string")
// using the getOrElse method
for (s <- strings) println( s.getOrElse("[null]") )
// using pattern matching
for (s <- strings) {
s match {
case Some(s:String) => println(s)
case None => println("[null]")
// The default case is useless because strings is of type List[Option[String]]
// and the match is exhaustive with Some[String] and None
//case _ =>
}
}
Obviously some Scala classes use the Option type. Let's have a look to the source code of the scala.collection.Map class:
/** Check if this map mapsYou can see that the return type of the get method is Option[B] (where B is the type of the value associated with the key).keyto a value and return the * value if it exists. * * @param key the key of the mapping of interest * @return the value of the mapping, if it exists */ def get(key: A): Option[B] /** Check if this map mapskeyto a value. * Return that value if it exists, otherwise returndefault. */ def getOrElse[B2 >: B](key: A, default: => B2): B2 = get(key) match { case Some(v) => v case None => default }
The getOrElse method calls the get method directly and matches the proper Option[B] pattern as shown in the previous example. The passed-in default function is invoked when the value associated with the key matches None (i.e. the key is not referenced within the map).
Here is a last example using the Map collection:
val stocks = Map (
"Google" -> "GOOG",
"Yahoo!" -> "YHOO",
"IBM" -> "IBM",
"Oracle" -> "ORCL"
)
val notFound = "[unknown]";
println(stocks.getOrElse("Yahoo!", notFound))
println(stocks.getOrElse("Apple", notFound))
This code produces the following output:
YHOO
[unknown]
[unknown]
For more information, please have a look to this article from David Pollack about a concrete use of the Option type within the Lift framework.
- Tags:
