Some(slides)
val reasonsToUseNull = None
Friday, July 19, 13
Who am I?
Java (& Scala) Developer at Schantz A/S
Polyglot curious, Coursera junkie
Interested in HCI and Usability
https://github.com/JKrag
@jankrag
• Geek, builder and flyer of kites, reptile & cat breeder, Rubik's puzzle fan
Friday, July 19, 13
Oh we wish...
val customer = Customers.findById(1234)
customer.getAccount(FUNSTUFF).getLastInterest.getAmount
Friday, July 19, 13
Oh we wish...
val customer = Customers.findById(1234)
customer.getAccount(FUNSTUFF).getLastInterest.getAmount
NullPointers !
Friday, July 19, 13
Classic solutions (java)
Friday, July 19, 13
Classic solutions (java)
Nested if’s
if(customer != null {
! if(customer.getAccount(FUNSTUFF) != null) {
! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) {
! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
! ! }
! }
}
return null;
Friday, July 19, 13
Classic solutions (java)
Nested if’s
if(customer != null {
! if(customer.getAccount(FUNSTUFF) != null) {
! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) {
! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
! ! }
! }
}
return null; UGLY
Friday, July 19, 13
Classic solutions (java)
Nested if’s
if(customer != null {
! if(customer.getAccount(FUNSTUFF) != null) {
! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) {
! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
! ! }
! }
}
return null;
Early returns
if (customer == null) return null;
if (customer.getAccount(FUNSTUFF) == null) return null;
if (customer.getAccount(FUNSTUFF).getLastInterest == null) return null;
return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
UGLY
Friday, July 19, 13
Classic solutions (java)
Nested if’s
if(customer != null {
! if(customer.getAccount(FUNSTUFF) != null) {
! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) {
! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
! ! }
! }
}
return null;
Early returns
if (customer == null) return null;
if (customer.getAccount(FUNSTUFF) == null) return null;
if (customer.getAccount(FUNSTUFF).getLastInterest == null) return null;
return customer.getAccount(FUNSTUFF).getLastInterest.getAmount
UGLY
Still UGLY!
Friday, July 19, 13
Same in Scala
Friday, July 19, 13
Same in Scala
val customer = Customers.findById(1234)
if (customer != null) {
! val account = customer.account(FUNSTUFF);
! if (account != null) {
! ! val interest = account.getLastInterest
! ! if (interest != null)
! ! ! interest.amount
! ! else
! ! ! null
! } else
! ! null
} else
! null
Friday, July 19, 13
Same in Scala
val customer = Customers.findById(1234)
if (customer != null) {
! val account = customer.account(FUNSTUFF);
! if (account != null) {
! ! val interest = account.getLastInterest
! ! if (interest != null)
! ! ! interest.amount
! ! else
! ! ! null
! } else
! ! null
} else
! null
Even in Scala,
Still UGLY!
Friday, July 19, 13
Same in Scala
val customer = Customers.findById(1234)
if (customer != null) {
! val account = customer.account(FUNSTUFF);
! if (account != null) {
! ! val interest = account.getLastInterest
! ! if (interest != null)
! ! ! interest.amount
! ! else
! ! ! null
! } else
! ! null
} else
! null
Even in Scala,
Still UGLY!
...and
errorprone
Friday, July 19, 13
non-existence
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Groovy (et al.)
Safe navigation operator
def amount = customer?.account?.interest?.amount
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Groovy (et al.)
Safe navigation operator
def amount = customer?.account?.interest?.amount
Ceylon, Kotlin etc.
both nullable and null-safe types...
String name = null; //compile error: null is not an instance of String
String? name = null; //OK
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Groovy (et al.)
Safe navigation operator
def amount = customer?.account?.interest?.amount
Ceylon, Kotlin etc.
both nullable and null-safe types...
String name = null; //compile error: null is not an instance of String
String? name = null; //OK
Others (e.g. Clojure): ‘nil’ type - close but...!
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Groovy (et al.)
Safe navigation operator
def amount = customer?.account?.interest?.amount
Ceylon, Kotlin etc.
both nullable and null-safe types...
String name = null; //compile error: null is not an instance of String
String? name = null; //OK
Others (e.g. Clojure): ‘nil’ type - close but...!
Scala ....
Friday, July 19, 13
non-existence
Java
null, null, null, null :-(
Groovy (et al.)
Safe navigation operator
def amount = customer?.account?.interest?.amount
Ceylon, Kotlin etc.
both nullable and null-safe types...
String name = null; //compile error: null is not an instance of String
String? name = null; //OK
Others (e.g. Clojure): ‘nil’ type - close but...!
Scala .... patience...
Friday, July 19, 13
We need something
like:
Container
Empty
container
Important: Same ‘shape’ outside
Friday, July 19, 13
Let me present:
Friday, July 19, 13
Let me present:
Option monad
Friday, July 19, 13
Let me present:
Option monadSHHH
Friday, July 19, 13
Scala’s Option type:
Some(2) None
Friday, July 19, 13
Option - concept
sealed trait Option[A]
case class Some[A](a: A) extends Option[A]
case class None[A] extends Option[A]
Friday, July 19, 13
Advantages
• Values that may or may not exist now
stated in type system
• Clearly shows possible non-existence
• Compiler forces you to deal with it
• You won’t accidentally rely on value
Friday, July 19, 13
Option - in RL
sealed abstract class Option[A] extends Product
case class Some[+A](a: A) extends Option[A]
case object None extends Option[Nothing]
Friday, July 19, 13
Option - in RL
sealed abstract class Option[A] extends Product {
def isEmpty: Boolean
def get: A
...
}
final case class Some[+A](x: A) extends Option[A] {
def isEmpty = false
def get = x
}
case object None extends Option[Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("None.get")
}
Friday, July 19, 13
WAT?
Friday, July 19, 13
Creating Options
Friday, July 19, 13
Creating Options
• Direct: !
val o = Some(3)
//> o : Option[Int] = Some(3)
val n = None
//> n : None.type = None
Friday, July 19, 13
BUT NEVER: val aaargh = Some(null)
Creating Options
• Direct: !
val o = Some(3)
//> o : Option[Int] = Some(3)
val n = None
//> n : None.type = None
Friday, July 19, 13
BUT NEVER: val aaargh = Some(null)
Creating Options
• Direct: !
val o = Some(3)
//> o : Option[Int] = Some(3)
val n = None
//> n : None.type = None
• Factory method on companion object: !
val o = Option(3)
//> o : Option[Int] = Some(3)
val nn = Option(null)
//> nn : Option[Null] = None
Friday, July 19, 13
val schroedingersBox : Option[Cat] =
! if(random.nextBoolean) then
Some(Garfield)
else
None
Friday, July 19, 13
Many mays to use
• isDefined
• isEmpty
Friday, July 19, 13
Many mays to use
• isDefined
• isEmpty
if (customer.isDefined)
! customer.account;
Friday, July 19, 13
Many mays to use
• isDefined
• isEmpty
if (customer.isDefined)
! customer.account;
Much more type-safe and null-safe
than original null-based java-flavour,
but code just as ugly
Friday, July 19, 13
get?
three.get
! //> res10: Int = 3
nope.get
! //> java.util.NoSuchElementException: None.get
Friday, July 19, 13
get?
three.get
! //> res10: Int = 3
nope.get
! //> java.util.NoSuchElementException: None.get
$> Yay. We can still write the other
ugly version with Exception
handling :-)
Friday, July 19, 13
Apprentice level:
Pattern matching
Friday, July 19, 13
Apprentice level:
Pattern matching
val foo = request.param("foo") match
{
! case Some(foo) => foo
! case None => "Default foo"
}
Friday, July 19, 13
Apprentice level:
Pattern matching
val foo = request.param("foo") match
{
! case Some(foo) => foo
! case None => "Default foo"
}
Sometimes useful, but...
Friday, July 19, 13
Apprentice level:
Pattern matching
val foo = request.param("foo") match
{
! case Some(foo) => foo
! case None => "Default foo"
}
Sometimes useful, but...
at some point a Jedi you must become
Friday, July 19, 13
What we really want is
Friday, July 19, 13
What we really want is
... to do stuff with our values
Friday, July 19, 13
What we really want is
... to do stuff with our values
Friday, July 19, 13
But...
Friday, July 19, 13
We want...?
Friday, July 19, 13
Padawan level:
functional
• Treat Option as a (very small) collection
• “Biased” towards Some
• map, flatMap etc.
• and compose to your desire when the
option contains a value
Friday, July 19, 13
map
Friday, July 19, 13
map
! val three = Some(3)
! ! ! ! > three : Option[Int] = Some(3)
Friday, July 19, 13
map
! val three = Some(3)
! ! ! ! > three : Option[Int] = Some(3)
! val res = three.map(_ + 3)
Friday, July 19, 13
map
! val three = Some(3)
! ! ! ! > three : Option[Int] = Some(3)
! val res = three.map(_ + 3)
> res: Option[Int] = Some(6)
Friday, July 19, 13
map
option.map(foo(_))
equivalent to:
option match {
case None => None
case Some(x) => Some(foo(x))
}
Friday, July 19, 13
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
//> res4: Option[Int] = Some(9)
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
//> res4: Option[Int] = Some(9)
three.map(sqr(_))
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
//> res4: Option[Int] = Some(9)
three.map(sqr(_))
//> res5: Option[Int] = Some(9)
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
//> res4: Option[Int] = Some(9)
three.map(sqr(_))
//> res5: Option[Int] = Some(9)
three.map(sqr)
Examples
Friday, July 19, 13
def sqr(i:Int) = {i*i}
val three = Option(3)
three.map(i => sqr(i))
//> res4: Option[Int] = Some(9)
three.map(sqr(_))
//> res5: Option[Int] = Some(9)
three.map(sqr)
//> res6: Option[Int] = Some(9)
Examples
Friday, July 19, 13
flatMap
option.flatMap(foo(_))
is equivalent to:
option match {
case None => None
case Some(x) => foo(x)
}
Friday, July 19, 13
three.flatMap(x => Some(x.toString))
Option[java.lang.String] = Some(3)
nah.flatMap(x => Some(x.toString))
Option[java.lang.String] = None
Friday, July 19, 13
Side effects:
foreach
option.foreach(foo(_))
is equivalent to:
option match {
case None => {}
case Some(x) => foo(x)
}
Friday, July 19, 13
three.foreach(println(_))
Friday, July 19, 13
val userOpt = UserDao.findById(userId)
userOpt.foreach(user => println(user.name))
or, even shorter:
userOpt.foreach(println)
Friday, July 19, 13
Working with lists
val o1 = Option(1)! ! //> o1 : Option[Int] = Some(1)
val o2 = Option(2) //> o2 : Option[Int] = Some(2)
val o3 = Option(3) //> o3 : Option[Int] = Some(3)
val l = List(o1, nope, o2, nah, o3)
! //> l : List[Option[Int]]
= List(Some(1), None, Some(2), None, Some(3))
!
l.map(_.map(sqr))
! ! //> res8: List[Option[Int]]
= List(Some(1), None, Some(4), None, Some(9))
l.flatMap(_.map(sqr))
! ! //> res9: List[Int] = List(1, 4, 9)
Friday, July 19, 13
Jedi level:
for comprehesions
val ageOpt = for {
! user <- UserDao.findById(userId)
! age <- user.ageOpt
} yield age
Friday, July 19, 13
Jedi mind tricks
//we have a ‘User’ with mandatory name, but optional age
case class User(val name:String , val age:Option[Int])
def prettyPrint(user: User) =
! List(Option(user.name), user.age).flatten.mkString(", ")
val foo = User("Foo", Some(42))
val bar = User("Bar", None)
prettyPrint(foo) //prints "Foo, 42"
prettyPrint(bar) //prints "Bar"
Friday, July 19, 13
val userOpt =
UserDao.findById(userId) OrElse Some(UserDao.create)
or:
val user =
UserDao.findById(userId) getOrElse UserDao.create
Friday, July 19, 13
other option options
def filter(p: A => Boolean): Option[A]
def exists(p: A => Boolean): Boolean
fold
collect
iterator
toList
Friday, July 19, 13
Resources
References, Thanks, Resources and further
reading
Attributions:
Thanks to Adit Bhargava for a great blogpost on monads in Haskel and for letting me
use his cartoon drawings:
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
For broadening my mind on higher-order use of Options: http://blog.tmorris.net/posts/
scalaoption-cheat-sheet/
Further reading
http://marakana.com/static/courseware/scala/presentation/comprehending-monads.html
http://blog.xebia.com/2011/06/02/scala-options-the-slick-way/
Friday, July 19, 13

Introduction to Option monad in Scala

  • 1.
    Some(slides) val reasonsToUseNull =None Friday, July 19, 13
  • 2.
    Who am I? Java(& Scala) Developer at Schantz A/S Polyglot curious, Coursera junkie Interested in HCI and Usability https://github.com/JKrag @jankrag • Geek, builder and flyer of kites, reptile & cat breeder, Rubik's puzzle fan Friday, July 19, 13
  • 3.
    Oh we wish... valcustomer = Customers.findById(1234) customer.getAccount(FUNSTUFF).getLastInterest.getAmount Friday, July 19, 13
  • 4.
    Oh we wish... valcustomer = Customers.findById(1234) customer.getAccount(FUNSTUFF).getLastInterest.getAmount NullPointers ! Friday, July 19, 13
  • 5.
  • 6.
    Classic solutions (java) Nestedif’s if(customer != null { ! if(customer.getAccount(FUNSTUFF) != null) { ! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) { ! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount ! ! } ! } } return null; Friday, July 19, 13
  • 7.
    Classic solutions (java) Nestedif’s if(customer != null { ! if(customer.getAccount(FUNSTUFF) != null) { ! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) { ! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount ! ! } ! } } return null; UGLY Friday, July 19, 13
  • 8.
    Classic solutions (java) Nestedif’s if(customer != null { ! if(customer.getAccount(FUNSTUFF) != null) { ! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) { ! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount ! ! } ! } } return null; Early returns if (customer == null) return null; if (customer.getAccount(FUNSTUFF) == null) return null; if (customer.getAccount(FUNSTUFF).getLastInterest == null) return null; return customer.getAccount(FUNSTUFF).getLastInterest.getAmount UGLY Friday, July 19, 13
  • 9.
    Classic solutions (java) Nestedif’s if(customer != null { ! if(customer.getAccount(FUNSTUFF) != null) { ! ! if(customer.getAccount(FUNSTUFF).getLastInterest != null) { ! ! ! return customer.getAccount(FUNSTUFF).getLastInterest.getAmount ! ! } ! } } return null; Early returns if (customer == null) return null; if (customer.getAccount(FUNSTUFF) == null) return null; if (customer.getAccount(FUNSTUFF).getLastInterest == null) return null; return customer.getAccount(FUNSTUFF).getLastInterest.getAmount UGLY Still UGLY! Friday, July 19, 13
  • 10.
  • 11.
    Same in Scala valcustomer = Customers.findById(1234) if (customer != null) { ! val account = customer.account(FUNSTUFF); ! if (account != null) { ! ! val interest = account.getLastInterest ! ! if (interest != null) ! ! ! interest.amount ! ! else ! ! ! null ! } else ! ! null } else ! null Friday, July 19, 13
  • 12.
    Same in Scala valcustomer = Customers.findById(1234) if (customer != null) { ! val account = customer.account(FUNSTUFF); ! if (account != null) { ! ! val interest = account.getLastInterest ! ! if (interest != null) ! ! ! interest.amount ! ! else ! ! ! null ! } else ! ! null } else ! null Even in Scala, Still UGLY! Friday, July 19, 13
  • 13.
    Same in Scala valcustomer = Customers.findById(1234) if (customer != null) { ! val account = customer.account(FUNSTUFF); ! if (account != null) { ! ! val interest = account.getLastInterest ! ! if (interest != null) ! ! ! interest.amount ! ! else ! ! ! null ! } else ! ! null } else ! null Even in Scala, Still UGLY! ...and errorprone Friday, July 19, 13
  • 14.
  • 15.
    non-existence Java null, null, null,null :-( Friday, July 19, 13
  • 16.
    non-existence Java null, null, null,null :-( Groovy (et al.) Safe navigation operator def amount = customer?.account?.interest?.amount Friday, July 19, 13
  • 17.
    non-existence Java null, null, null,null :-( Groovy (et al.) Safe navigation operator def amount = customer?.account?.interest?.amount Ceylon, Kotlin etc. both nullable and null-safe types... String name = null; //compile error: null is not an instance of String String? name = null; //OK Friday, July 19, 13
  • 18.
    non-existence Java null, null, null,null :-( Groovy (et al.) Safe navigation operator def amount = customer?.account?.interest?.amount Ceylon, Kotlin etc. both nullable and null-safe types... String name = null; //compile error: null is not an instance of String String? name = null; //OK Others (e.g. Clojure): ‘nil’ type - close but...! Friday, July 19, 13
  • 19.
    non-existence Java null, null, null,null :-( Groovy (et al.) Safe navigation operator def amount = customer?.account?.interest?.amount Ceylon, Kotlin etc. both nullable and null-safe types... String name = null; //compile error: null is not an instance of String String? name = null; //OK Others (e.g. Clojure): ‘nil’ type - close but...! Scala .... Friday, July 19, 13
  • 20.
    non-existence Java null, null, null,null :-( Groovy (et al.) Safe navigation operator def amount = customer?.account?.interest?.amount Ceylon, Kotlin etc. both nullable and null-safe types... String name = null; //compile error: null is not an instance of String String? name = null; //OK Others (e.g. Clojure): ‘nil’ type - close but...! Scala .... patience... Friday, July 19, 13
  • 21.
    We need something like: Container Empty container Important:Same ‘shape’ outside Friday, July 19, 13
  • 22.
  • 23.
    Let me present: Optionmonad Friday, July 19, 13
  • 24.
    Let me present: OptionmonadSHHH Friday, July 19, 13
  • 25.
    Scala’s Option type: Some(2)None Friday, July 19, 13
  • 26.
    Option - concept sealedtrait Option[A] case class Some[A](a: A) extends Option[A] case class None[A] extends Option[A] Friday, July 19, 13
  • 27.
    Advantages • Values thatmay or may not exist now stated in type system • Clearly shows possible non-existence • Compiler forces you to deal with it • You won’t accidentally rely on value Friday, July 19, 13
  • 28.
    Option - inRL sealed abstract class Option[A] extends Product case class Some[+A](a: A) extends Option[A] case object None extends Option[Nothing] Friday, July 19, 13
  • 29.
    Option - inRL sealed abstract class Option[A] extends Product { def isEmpty: Boolean def get: A ... } final case class Some[+A](x: A) extends Option[A] { def isEmpty = false def get = x } case object None extends Option[Nothing] { def isEmpty = true def get = throw new NoSuchElementException("None.get") } Friday, July 19, 13
  • 30.
  • 31.
  • 32.
    Creating Options • Direct:! val o = Some(3) //> o : Option[Int] = Some(3) val n = None //> n : None.type = None Friday, July 19, 13
  • 33.
    BUT NEVER: valaaargh = Some(null) Creating Options • Direct: ! val o = Some(3) //> o : Option[Int] = Some(3) val n = None //> n : None.type = None Friday, July 19, 13
  • 34.
    BUT NEVER: valaaargh = Some(null) Creating Options • Direct: ! val o = Some(3) //> o : Option[Int] = Some(3) val n = None //> n : None.type = None • Factory method on companion object: ! val o = Option(3) //> o : Option[Int] = Some(3) val nn = Option(null) //> nn : Option[Null] = None Friday, July 19, 13
  • 35.
    val schroedingersBox :Option[Cat] = ! if(random.nextBoolean) then Some(Garfield) else None Friday, July 19, 13
  • 36.
    Many mays touse • isDefined • isEmpty Friday, July 19, 13
  • 37.
    Many mays touse • isDefined • isEmpty if (customer.isDefined) ! customer.account; Friday, July 19, 13
  • 38.
    Many mays touse • isDefined • isEmpty if (customer.isDefined) ! customer.account; Much more type-safe and null-safe than original null-based java-flavour, but code just as ugly Friday, July 19, 13
  • 39.
    get? three.get ! //> res10:Int = 3 nope.get ! //> java.util.NoSuchElementException: None.get Friday, July 19, 13
  • 40.
    get? three.get ! //> res10:Int = 3 nope.get ! //> java.util.NoSuchElementException: None.get $> Yay. We can still write the other ugly version with Exception handling :-) Friday, July 19, 13
  • 41.
  • 42.
    Apprentice level: Pattern matching valfoo = request.param("foo") match { ! case Some(foo) => foo ! case None => "Default foo" } Friday, July 19, 13
  • 43.
    Apprentice level: Pattern matching valfoo = request.param("foo") match { ! case Some(foo) => foo ! case None => "Default foo" } Sometimes useful, but... Friday, July 19, 13
  • 44.
    Apprentice level: Pattern matching valfoo = request.param("foo") match { ! case Some(foo) => foo ! case None => "Default foo" } Sometimes useful, but... at some point a Jedi you must become Friday, July 19, 13
  • 45.
    What we reallywant is Friday, July 19, 13
  • 46.
    What we reallywant is ... to do stuff with our values Friday, July 19, 13
  • 47.
    What we reallywant is ... to do stuff with our values Friday, July 19, 13
  • 48.
  • 49.
  • 50.
    Padawan level: functional • TreatOption as a (very small) collection • “Biased” towards Some • map, flatMap etc. • and compose to your desire when the option contains a value Friday, July 19, 13
  • 51.
  • 52.
    map ! val three= Some(3) ! ! ! ! > three : Option[Int] = Some(3) Friday, July 19, 13
  • 53.
    map ! val three= Some(3) ! ! ! ! > three : Option[Int] = Some(3) ! val res = three.map(_ + 3) Friday, July 19, 13
  • 54.
    map ! val three= Some(3) ! ! ! ! > three : Option[Int] = Some(3) ! val res = three.map(_ + 3) > res: Option[Int] = Some(6) Friday, July 19, 13
  • 55.
    map option.map(foo(_)) equivalent to: option match{ case None => None case Some(x) => Some(foo(x)) } Friday, July 19, 13
  • 56.
  • 57.
    def sqr(i:Int) ={i*i} Examples Friday, July 19, 13
  • 58.
    def sqr(i:Int) ={i*i} val three = Option(3) Examples Friday, July 19, 13
  • 59.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) Examples Friday, July 19, 13
  • 60.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) //> res4: Option[Int] = Some(9) Examples Friday, July 19, 13
  • 61.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) //> res4: Option[Int] = Some(9) three.map(sqr(_)) Examples Friday, July 19, 13
  • 62.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) //> res4: Option[Int] = Some(9) three.map(sqr(_)) //> res5: Option[Int] = Some(9) Examples Friday, July 19, 13
  • 63.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) //> res4: Option[Int] = Some(9) three.map(sqr(_)) //> res5: Option[Int] = Some(9) three.map(sqr) Examples Friday, July 19, 13
  • 64.
    def sqr(i:Int) ={i*i} val three = Option(3) three.map(i => sqr(i)) //> res4: Option[Int] = Some(9) three.map(sqr(_)) //> res5: Option[Int] = Some(9) three.map(sqr) //> res6: Option[Int] = Some(9) Examples Friday, July 19, 13
  • 65.
    flatMap option.flatMap(foo(_)) is equivalent to: optionmatch { case None => None case Some(x) => foo(x) } Friday, July 19, 13
  • 66.
    three.flatMap(x => Some(x.toString)) Option[java.lang.String]= Some(3) nah.flatMap(x => Some(x.toString)) Option[java.lang.String] = None Friday, July 19, 13
  • 67.
    Side effects: foreach option.foreach(foo(_)) is equivalentto: option match { case None => {} case Some(x) => foo(x) } Friday, July 19, 13
  • 68.
  • 69.
    val userOpt =UserDao.findById(userId) userOpt.foreach(user => println(user.name)) or, even shorter: userOpt.foreach(println) Friday, July 19, 13
  • 70.
    Working with lists valo1 = Option(1)! ! //> o1 : Option[Int] = Some(1) val o2 = Option(2) //> o2 : Option[Int] = Some(2) val o3 = Option(3) //> o3 : Option[Int] = Some(3) val l = List(o1, nope, o2, nah, o3) ! //> l : List[Option[Int]] = List(Some(1), None, Some(2), None, Some(3)) ! l.map(_.map(sqr)) ! ! //> res8: List[Option[Int]] = List(Some(1), None, Some(4), None, Some(9)) l.flatMap(_.map(sqr)) ! ! //> res9: List[Int] = List(1, 4, 9) Friday, July 19, 13
  • 71.
    Jedi level: for comprehesions valageOpt = for { ! user <- UserDao.findById(userId) ! age <- user.ageOpt } yield age Friday, July 19, 13
  • 72.
    Jedi mind tricks //wehave a ‘User’ with mandatory name, but optional age case class User(val name:String , val age:Option[Int]) def prettyPrint(user: User) = ! List(Option(user.name), user.age).flatten.mkString(", ") val foo = User("Foo", Some(42)) val bar = User("Bar", None) prettyPrint(foo) //prints "Foo, 42" prettyPrint(bar) //prints "Bar" Friday, July 19, 13
  • 73.
    val userOpt = UserDao.findById(userId)OrElse Some(UserDao.create) or: val user = UserDao.findById(userId) getOrElse UserDao.create Friday, July 19, 13
  • 74.
    other option options deffilter(p: A => Boolean): Option[A] def exists(p: A => Boolean): Boolean fold collect iterator toList Friday, July 19, 13
  • 75.
    Resources References, Thanks, Resourcesand further reading Attributions: Thanks to Adit Bhargava for a great blogpost on monads in Haskel and for letting me use his cartoon drawings: http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html For broadening my mind on higher-order use of Options: http://blog.tmorris.net/posts/ scalaoption-cheat-sheet/ Further reading http://marakana.com/static/courseware/scala/presentation/comprehending-monads.html http://blog.xebia.com/2011/06/02/scala-options-the-slick-way/ Friday, July 19, 13