Instructor: James Riely
Option[T]
resembles List[T]
with length ≤ 1
Option[Int]
None
Some (5)
def getDirs1 (dirName : String) : List[java.io.File] =
val dir = new java.io.File (dirName)
val xs = dir.listFiles
if xs == null then throw new java.io.FileNotFoundException
xs.toList.filter (_.isDirectory)
getDirs1 ("/tmp")
res1: List[java.io.File] = List(/tmp/log, /tmp/cache)
getDirs1 ("/temp")
java.io.FileNotFoundException
def getDirs2 (dirName : String) : Option[List[java.io.File]] =
val dir = new java.io.File (dirName)
val xs = dir.listFiles
if xs == null then return None
Some(xs.toList.filter (_.isDirectory))
getDirs2 ("/tmp")
res2: Option[List[java.io.File]] = Some(List(/tmp/log, /tmp/cache))
getDirs ("/temp")
res3: Option[List[java.io.File]] = None
def printNumTemp1 () =
var result : List[java.io.File] = Nil
var found = false
for s <- List("/temp", "/tmp"); if !found do
try
result = getDirs1(s)
found = true
catch
case e: java.io.FileNotFoundException => ()
found match
case false => println("No Temporary Directory.")
case true => println(result.length)
def printNumTemp2 () =
getDirs2("/temp") orElse getDirs2("/tmp") match
case None => println("No Temporary Directory.")
case Some(result) => println(result.length)
Option
None
: empty option
Nil
: empty list
null
: reference to nothing
Unit
is not an option type
Unit
always has nothing
Unit
nothing is ()
Nil
def sum (xs : List[Int]) : Int = xs match
case Nil => 0
case y::ys => y + sum(ys)
null
int sum (Node<Integer> xs)
if (xs == null) return 0;
else return xs.head + sum(xs.tail);
null
does not exist
-Yexplicit-nulls
T|Null
var a: String = "abc"
a = null /* compilation error */
a.length /* always safe */
var b: String|Null = "abc"
b = null /* ok */
b.length /* compiler error */
b.nn.length /* may give Null Pointer Exception */
if b != null then b.nn.length else null /* Safe call with result Int|Null */
if b != null then b.nn.length else -1 /* Safe call with result Int */
T?
means T|Null
?
do not allow null
var a: String = "abc"
a = null /* compilation error */
a.length /* always safe */
var b: String? = "abc"
b = null /* ok */
b.length /* compiler error */
b!!.length /* may give Null Pointer Exception */
b?.length /* Safe call with result Int? */
if (b != null) b.length else null /* expanded */
b?.length ?: -1 /* Safe call with result Int */
val t = b?.length; if (t != null) t else -1 /* expanded */
Java 8 added java.util.Optional
The intended use is narrow:
Optional is intended to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result," and using null for such was overwhelmingly likely to cause errors.
def map[X,Y](maybe_x:Option[X], f:X=>Option[Y]) : Option[Option[Y]] =
maybe_x match
case None => None
case Some(x) => Some(f(x))
def flatMap[X,Y](maybe_x:Option[X], f:X=>Option[Y]) : Option[Y] =
maybe_x match
case None => None
case Some(x) =>
val result : Option[Y] = f(x)
result match
case None => None
case Some (y) => Some(y)
def index [X] (xs:List[X], n:Int) : Option[X] =
xs match
case Nil => None
case y::_ if n == 0 => Some (y)
case _::ys => index (ys, n - 1)
def safeDivide (n:Int,m:Int) : Option[Int] =
if m == 0 then None
else Some (n/m)
def as = List(11,21,31)
scala> map(index(as,2), safeDivide(_,2))
val res10: Option[Option[Int]] = Some(Some(15))
scala> flatMap(index(as,2), safeDivide(_,2))
val res11: Option[Int] = Some(15)
def index [X] (xs:List[X], n:Int) : Option[X] =
xs match
case Nil => None
case y::_ if n == 0 => Some (y)
case _::ys => index (ys, n - 1)
def safeDivide (n:Int,m:Int) : Option[Int] =
if m == 0 then None
else Some (n/m)
def as = List(11,21,31)
scala> for
a <- index(as,2)
b <- safeDivide(a,2)
yield b
val res11: Option[Int] = Some(15)