SlideShare una empresa de Scribd logo
1 de 75
Descargar para leer sin conexión
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

Más contenido relacionado

Destacado

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
 
Thinking functional-in-scala
Thinking functional-in-scalaThinking functional-in-scala
Thinking functional-in-scalaKnoldus Inc.
 
Functors, Applicatives and Monads In Scala
Functors, Applicatives and Monads In ScalaFunctors, Applicatives and Monads In Scala
Functors, Applicatives and Monads In ScalaKnoldus Inc.
 
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
 
Developers Summit 2015 - Scala Monad
Developers Summit 2015 - Scala MonadDevelopers Summit 2015 - Scala Monad
Developers Summit 2015 - Scala MonadSangwon Han
 
Advanced Functional Programming in Scala
Advanced Functional Programming in ScalaAdvanced Functional Programming in Scala
Advanced Functional Programming in ScalaPatrick Nicolas
 
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 mindSander Mak (@Sander_Mak)
 
Functional Programming Fundamentals
Functional Programming FundamentalsFunctional Programming Fundamentals
Functional Programming FundamentalsShahriar Hyder
 
AWS Primer and Quickstart
AWS Primer and QuickstartAWS Primer and Quickstart
AWS Primer and QuickstartManish Pandit
 

Destacado (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

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?Antenna Manufacturer Coco
 
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 2024The Digital Insurer
 
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...apidays
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
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 AutomationSafe Software
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
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...Miguel Araújo
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 

Ú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?
 
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
 
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...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
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
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
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)
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 

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