SlideShare uma empresa Scribd logo
1 de 75
Baixar para ler offline
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

Mais conteúdo relacionado

Destaque

Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
stasimus
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
stasimus
 

Destaque (11)

Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)Introduction to Monads in Scala (2)
Introduction to Monads in Scala (2)
 
Thinking functional-in-scala
Thinking functional-in-scalaThinking functional-in-scala
Thinking functional-in-scala
 
Functors, Applicatives and Monads In Scala
Functors, Applicatives and Monads In ScalaFunctors, Applicatives and Monads In Scala
Functors, Applicatives and Monads In Scala
 
Les monades Scala, Java 8
Les monades Scala, Java 8Les monades Scala, Java 8
Les monades Scala, Java 8
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Developers Summit 2015 - Scala Monad
Developers Summit 2015 - Scala MonadDevelopers Summit 2015 - Scala Monad
Developers Summit 2015 - Scala Monad
 
Advanced Functional Programming in Scala
Advanced Functional Programming in ScalaAdvanced Functional Programming in Scala
Advanced Functional Programming in Scala
 
Scala: functional programming for the imperative mind
Scala: functional programming for the imperative mindScala: functional programming for the imperative mind
Scala: functional programming for the imperative mind
 
Functional Programming Fundamentals
Functional Programming FundamentalsFunctional Programming Fundamentals
Functional Programming Fundamentals
 
AWS Primer and Quickstart
AWS Primer and QuickstartAWS Primer and Quickstart
AWS Primer and Quickstart
 
Exception Handling in Scala
Exception Handling in ScalaException Handling in Scala
Exception Handling in Scala
 

Último

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 

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... val customer = Customers.findById(1234) customer.getAccount(FUNSTUFF).getLastInterest.getAmount Friday, July 19, 13
  • 4. Oh we wish... val customer = Customers.findById(1234) customer.getAccount(FUNSTUFF).getLastInterest.getAmount NullPointers ! Friday, July 19, 13
  • 6. 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
  • 7. 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
  • 8. 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
  • 9. 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
  • 10. Same in Scala Friday, July 19, 13
  • 11. 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
  • 12. 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
  • 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
  • 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. Let me present: Friday, July 19, 13
  • 23. Let me present: Option monad Friday, July 19, 13
  • 24. Let me present: Option monadSHHH Friday, July 19, 13
  • 25. Scala’s Option type: Some(2) None Friday, July 19, 13
  • 26. 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
  • 27. 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
  • 28. 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
  • 29. 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
  • 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: 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
  • 34. 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
  • 35. val schroedingersBox : Option[Cat] = ! if(random.nextBoolean) then Some(Garfield) else None Friday, July 19, 13
  • 36. Many mays to use • isDefined • isEmpty Friday, July 19, 13
  • 37. Many mays to use • isDefined • isEmpty if (customer.isDefined) ! customer.account; Friday, July 19, 13
  • 38. 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
  • 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
  • 42. Apprentice level: Pattern matching val foo = request.param("foo") match { ! case Some(foo) => foo ! case None => "Default foo" } Friday, July 19, 13
  • 43. 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
  • 44. 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
  • 45. What we really want is Friday, July 19, 13
  • 46. What we really want is ... to do stuff with our values Friday, July 19, 13
  • 47. What we really want is ... to do stuff with our values Friday, July 19, 13
  • 50. 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
  • 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
  • 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: option match { 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 equivalent to: option match { case None => {} case Some(x) => foo(x) } Friday, July 19, 13
  • 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 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
  • 71. Jedi level: for comprehesions val ageOpt = for { ! user <- UserDao.findById(userId) ! age <- user.ageOpt } yield age Friday, July 19, 13
  • 72. 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
  • 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 def filter(p: A => Boolean): Option[A] def exists(p: A => Boolean): Boolean fold collect iterator toList Friday, July 19, 13
  • 75. 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