SlideShare une entreprise Scribd logo
1  sur  35
Télécharger pour lire hors ligne
Uncovering the Power of
Option, Either and Try
Scala for Beginners Series
Thursday, February 11, 2021
Why Scala?
ü Write clean, concise, powerful code — less boilerplate
ü Fast development, prototyping
ü Easier to write robust, fault-tolerant applications
ü Wizards use it
2
Copyright (C) 2021 Murray Todd Williams
Functional Programming
…a programming paradigm where programs are constructed by
applying and composing functions. It is a declarative programming
paradigm in which function definitions are trees of expressions that
map values to other values, rather than a sequence of imperative
statements which update the running state of the program.
Wikipedia
int x = 0;
while (data.ready()) {
int a = data.next();
if (a > 0) x += a * a;
}
data.filter(_ > 0)
.map(a => a * a)
.sum
3
Copyright (C) 2021 Murray Todd Williams
Quick advice for beginners: dump “var”
var x: Int = 1 // 1
x += 3 // now 4
val x: Int = 1
x += 3
• error: reassignment to val
Scala has two types of variable declarations:
If you really want to learn Scala, don’t let yourself ever use var. It will seem incredibly hard
at first. It may even seem impossible. (But it isn’t!) Eventually, your brain will make the
paradigm shift.
One hint: in some seemingly sticky situations, you’ll have to use recursion. It may seem weird,
but don’t fight it. You can indeed evict the evil vars!
4
Copyright (C) 2021 Murray Todd Williams
Writing robust, fault tolerant code
Java’s NullPointerException is about as popular and notorious
as the old BSOD.
How does Scala avoid it?
• All functions must return something (whatever type they declare)
• Variables (vals) don’t get defined with uninitialized state
• Functional programmers consider “unhappy paths”
5
Copyright (C) 2021 Murray Todd Williams
Option[T]
This is the easiest typeclass to understand:
val name: Option[String] = Some("Murray")
val name: Option[String] = None
It lets you consider cases where you may or may not have a value.
Consider looking up a name from a user database. What if the user
ID can’t be found?
def lookupName(id: String): Option[String]
6
Copyright (C) 2021 Murray Todd Williams
Option is found throughout Scala library
scala> val users = Map(1 -> "Alley", 2 -> "Sam")
scala> users.get(1)
val res0: Option[String] = Some(Alley)
scala> users.get(3)
val res1: Option[String] = None
scala> users(3)
java.util.NoSuchElementException: key not found: 3
at scala.collection.immutable.Map$Map2.apply(Map.scala:298)
... 32 elided
7
Copyright (C) 2021 Murray Todd Williams
Try[T]
This is next-most-natural way to handle things:
val name: Try[String] = Success("Murray")
val name: Try[String] = Failure(new Exception(…))
If you’re working with Java code or APIs where exceptions can be
thrown (even simple IOExceptions) you can wrap it in a Try call.
Try(db.lookup(name))
8
Copyright (C) 2021 Murray Todd Williams
Either[L,R]
Strictly, an Either typeclass lets you have one of two types.
def getAge(a: Int): Either[String,Int] =
if (a < 16)
Left("Renter is not old enought to drive.")
else Right(a)
scala> getAge(10)
val res0: Either[String,Int] = Left(Renter is not old enought to drive.)
scala> getAge(20)
val res1: Either[String,Int] = Right(20)
Conventionally, consider L to be the “unhappy path” and R to be the
“happy path”. (Pneumonic: think happy as what’s “right”)
9
Copyright (C) 2021 Murray Todd Williams
It can’t be too
hard to use…
I think I
get the gist
of this.
10
Copyright (C) 2021 Murray Todd Williams
Let’s try to apply Option to a typical situation…
scala> val users = Map(1 -> "Alley", 2 -> "Sam")
scala> val greeting = if (users.contains(1)) { "Hello " + users(1) }
val greeting: Any = Hello Alley
scala> val greeting = if (users.contains(1)) { "Hello " +
users.get(1) } else "Don't know"
val greeting: String = Hello Some(Alley)
scala> val greeting = if (users.contains(1)) { "Hello " +
users(1) } else "Don't know"
val greeting: String = Hello Alley
scala> val greeting = if (users.contains(1)) { Some("Hello " +
users(1)) } else None
val greeting: Option[String] = Some(Hello Alley)
11
Copyright (C) 2021 Murray Todd Williams
Let’s try something more realistic
case class Contact(id: Int, name: String, phone: Option[String],
email: Option[String], friendIds: List[Int]) {
import Contact._
/*
* Send an email to friends, inviting to join
* @return List of successfully sent emails
*/
def inviteFriends: List[Int] = ???
}
object Contact {
def sendEmail(email: String): Boolean = ???
def dbLookup(id: Int): Try[Contact] = ???
}
12
Copyright (C) 2021 Murray Todd Williams
Imperative (non-functional) approach
def inviteFriends(friendIds: List[Int]): List[Int] = {
var successes: List[Int] = List.empty
for (id <- friendIds) {
// lookup id from database
// if you can find it and it’s defined, send an email
// if it was successful, add the id to the successes list
}
successes
}
13
Copyright (C) 2021 Murray Todd Williams
Functional approach
Approach:
Start with a list of friend IDs to try
End up with a list of friend IDs from successful emails
Functional strategy:
Apply an operation (lookup & send) to each item in the list,
converting it into a success.
friendIds.map(id => lookupAndSendWithSuccess(id))
This is sort of what we want. We really want to shorten the list to
only have successful deliveries, but let’s not worry about that yet…
14
Copyright (C) 2021 Murray Todd Williams
First “functional” iteration
def inviteFriends: List[Int] = {
val successes = friendIds.map { id =>
dbLookup(id) match {
case Failure(_) => None
case Success(friend) => {
friend.email match {
case Some(email) => if (sendEmail(email)) Some(id) else None
case None => None
}
}
}
}
??? // success is now of type List[Option[Int]]
}
Happy
Path 1
Happy
Path 2
Happy
Path 3
Unhappy 1
Unhappy 2
Unhappy 3
15
Copyright (C) 2021 Murray Todd Williams
Yuck!
Can I just keep doing
imperative
programming?
Please!
You said Scala was
pretty, clean and
succinct!
16
Copyright (C) 2021 Murray Todd Williams
“Map” to the rescue!
Option[T].map(f: T => U) becomes Option[U]
Try[T].map(f: T => U) becomes Trt[U]
Either[L,R].map(f: R => S) becomes Either[L,S]
Let’s just write code snippets that
focus on the ”happy paths”
17
Copyright (C) 2021 Murray Todd Williams
“Map” to the rescue!
friend.email match {
case Some(email) => if (sendEmail(email)) Some(id) else None
case None => None
}
friend.email.map(e => sendEmail(e))
friend.email.map(sendEmail)
Let’s just write code snippets that
focus on the ”happy paths”
We get to think of e as a String (email)
rather than an Option[String]
To apply a function that only takes the
one parameter, you can simplify by just
supplying the function name.
18
Copyright (C) 2021 Murray Todd Williams
Second “functional” iteration
def inviteFriends: List[Int] = {
val successes = friendIds.map { id =>
dbLookup(id).map { contact =>
contact.email.map { address =>
sendEmail(address)
}
}
}
??? // successes is now of type List[Try[Option[Boolean]]]
}
Can I just keep doing
imperative programming?
This still doesn’t
look clean!
How do I work with a List of
Try[Option[Boolean]] ??
19
Copyright (C) 2021 Murray Todd Williams
Boxes within boxes! (Turtles all the way down)
Let’s start with 3 “safe” functions, each of which may or may not
yield a successful transformation.
f: A => Option[B]
g: B => Option[C]
h: C => Option[D]
We want to apply these in order, like f(x).map(g).map(h), but we don’t
want Option[Option[Option[D]]], we just want Option[D]
20
Copyright (C) 2021 Murray Todd Williams
“FlatMap” to the rescue!
scala> def getName(id: Int): Option[String] = users.get(id)
def getName(id: Int): Option[String]
scala> val id: Option[Int] = Some(2)
val id: Option[Int] = Some(2)
scala> id.flatMap(getName)
val res3: Option[String] = Some(Sam)
scala> val id: Option[Int] = Some(3)
val id: Option[Int] = Some(3)
scala> id.flatMap(getName)
val res2: Option[String] = None
21
Copyright (C) 2021 Murray Todd Williams
Think of Option, Try and Either as “Boxes”
T T T
Option[T]
Some[T] or
None
Try[T]
Success[T] or
Failure[E]
Either[S,T]
Right[T] or
Left[S]
22
Copyright (C) 2021 Murray Todd Williams
All use “map” to apply functions to their
contents.
f(t)
Option[T]
Some[T] or
None
Try[T]
Success[T] or
Failure[E]
Either[S,T]
Right[T] or
Left[S]
f(t) f(t)
(The functions are ignored if the boxes are empty)
23
Copyright (C) 2021 Murray Todd Williams
All use “flatMap” for functions that would
result in nested boxes.
t =>
(The functions are ignored if the boxes are empty)
f(t)
f(t)
flatMap only works if the boxes are
the same, so Options inside Options
24
Copyright (C) 2021 Murray Todd Williams
For multiple flatMap to work, keep the
boxes the same!
case class User(id: Int, email: Option[String])
def findUser(id: Int): Option[User]
def sendEmail(email: User): Option[String] // None if email fails
val sent = findUser(id).flatMap(_.email).flatMap(sendEmail)
send will be of type Option[String]
25
Copyright (C) 2021 Murray Todd Williams
Trick #1: Quick Convert Try[T] to Option[T]
case class User(id: Int, email: Option[String])
def findUser(id: Int): Try[User]
def sendEmail(user: User): Option[Int] // None if email fails
val sent = findUser(id).toOption
.flatMap(_.email).flatMap(sendEmail)
26
Copyright (C) 2021 Murray Todd Williams
Remember how we mapped on List?
T
T
T
T
T
T
List is just another type of
box, except it doesn’t hold
zero or one item of type T…
… it holds zero or more items
of type T.
Looks more like an egg
carton than a box!
27
Copyright (C) 2021 Murray Todd Williams
Remember how we mapped on List?
T
T
T
T
T
T
”map” applies a function to
each of the items
If your function generates its
own lists, flatMap “flattens”
them!
scala> val myList = List(3,2,1)
val myList: List[Int] = List(3, 2, 1)
scala> myList.map(x => List.fill(x)(x))
val res0: List[List[Int]] = List(List(3, 3, 3), List(2, 2), List(1))
scala> myList.flatMap(x => List.fill(x)(x))
val res1: List[Int] = List(3, 3, 3, 2, 2, 1)
28
Copyright (C) 2021 Murray Todd Williams
Options are also Lists!
Remember how we have to keep the ”boxes” the same for flatMap to
work? Well, if you have an Option[T], it doubles as a List[T] with
either zero (None) or one (Some(t)) elements!
val friends: List[Contact] = friendIds.flatMap(id => dbLookup(id).toOption)
val knownEmails: List[String] = friends.flatMap(_.email)
29
Copyright (C) 2021 Murray Todd Williams
We’re almost done!
def inviteFriends: List[Int] =
friendIds
.flatMap(id => dbLookup(id).toOption
.flatMap(contact => contact.email)
.filter(sendEmail).map(_ => id))
That’s not so bad, and I
do have all the built-in
safety stuff...
but I’m still not sold.
30
Copyright (C) 2021 Murray Todd Williams
Introducing For-comprehensions
def inviteFriends: List[Int] =
friendIds
.flatMap(id => dbLookup(id).toOption
.flatMap(contact => contact.email)
.filter(sendEmail).map(_ => id))
def inviteFriends: List[Int] = {
for {
id <- friendIds
contact <- dbLookup(id).toOption
e <- contact.email
status = sendEmail(e)
if status
} yield(id)
}
31
Copyright (C) 2021 Murray Todd Williams
Looking at the syntax in-depth
These are flatMap operations
<-
A simple map (not flatMap) is represented by =
”if” statements translate to .filter statements
Wow.
Whatever type of Box we
start with dictates the rest
of the Boxes
32
Copyright (C) 2021 Murray Todd Williams
def inviteFriends: List[Int] = {
for {
id <- friendIds
contact <- dbLookup(id).toOption
e <- contact.email
status = sendEmail(e)
if status
} yield(id)
}
Summary
• If you’re going to learn FP, start with banishing “var”
• Everything is a composition of functions
• Rather than iterating on lists, use “map” and “filter” and just
transform them through your various stages
• Handle potential ‘issues’ with Option, Try or Either
• Operate on their contents by using ”map” and focusing on the
happy path
• FlatMap keeps you from boxing (nesting) your boxes
• for-comprehensions create super-clean syntax for all of this
Copyright (C) 2021 Murray Todd Williams 33
Unveiling my Evil Master Plan…
Copyright (C) 2021 Murray Todd Williams 34
All your base are belong to us
You just
learned about
Monads
A monad is a kind of typeclass that “boxes” any
other type
It has .map that applies functions to the
contents of the boxes
It has .flatMap for functions that create their
own boxes in order to avoid nesting problems
Option, Try, Either and Future are good examples
of Monads
They isolate “pure functions” from problematic
contexts like asynchronous operations,
exception handling, missing data, etc.

Contenu connexe

Similaire à Beginning-Scala-Options-Either-Try.pdf

DataFrame in Python Pandas
DataFrame in Python PandasDataFrame in Python Pandas
DataFrame in Python PandasSangita Panchal
 
R tutorial for a windows environment
R tutorial for a windows environmentR tutorial for a windows environment
R tutorial for a windows environmentYogendra Chaubey
 
C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0Yaser Zhian
 
Introduction to matlab lecture 4 of 4
Introduction to matlab lecture 4 of 4Introduction to matlab lecture 4 of 4
Introduction to matlab lecture 4 of 4Randa Elanwar
 
Basic R Data Manipulation
Basic R Data ManipulationBasic R Data Manipulation
Basic R Data ManipulationChu An
 
Class 12 computer sample paper with answers
Class 12 computer sample paper with answersClass 12 computer sample paper with answers
Class 12 computer sample paper with answersdebarghyamukherjee60
 
More expressive types for spark with frameless
More expressive types for spark with framelessMore expressive types for spark with frameless
More expressive types for spark with framelessMiguel Pérez Pasalodos
 
Introduction to R
Introduction to RIntroduction to R
Introduction to RRajib Layek
 
R_CheatSheet.pdf
R_CheatSheet.pdfR_CheatSheet.pdf
R_CheatSheet.pdfMariappanR3
 
Scala 3 enum for a terser Option Monad Algebraic Data Type
Scala 3 enum for a terser Option Monad Algebraic Data TypeScala 3 enum for a terser Option Monad Algebraic Data Type
Scala 3 enum for a terser Option Monad Algebraic Data TypePhilip Schwarz
 
Class 31: Deanonymizing
Class 31: DeanonymizingClass 31: Deanonymizing
Class 31: DeanonymizingDavid Evans
 
Sample presentation slides template
Sample presentation slides templateSample presentation slides template
Sample presentation slides templateValerii Klymchuk
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitTomer Gabel
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala MakeoverGarth Gilmour
 

Similaire à Beginning-Scala-Options-Either-Try.pdf (20)

DataFrame in Python Pandas
DataFrame in Python PandasDataFrame in Python Pandas
DataFrame in Python Pandas
 
R tutorial for a windows environment
R tutorial for a windows environmentR tutorial for a windows environment
R tutorial for a windows environment
 
C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0C++11 - A Change in Style - v2.0
C++11 - A Change in Style - v2.0
 
Introduction to matlab lecture 4 of 4
Introduction to matlab lecture 4 of 4Introduction to matlab lecture 4 of 4
Introduction to matlab lecture 4 of 4
 
R Basics
R BasicsR Basics
R Basics
 
Basic R Data Manipulation
Basic R Data ManipulationBasic R Data Manipulation
Basic R Data Manipulation
 
Es272 ch1
Es272 ch1Es272 ch1
Es272 ch1
 
Class 12 computer sample paper with answers
Class 12 computer sample paper with answersClass 12 computer sample paper with answers
Class 12 computer sample paper with answers
 
More expressive types for spark with frameless
More expressive types for spark with framelessMore expressive types for spark with frameless
More expressive types for spark with frameless
 
Introduction to R
Introduction to RIntroduction to R
Introduction to R
 
R_CheatSheet.pdf
R_CheatSheet.pdfR_CheatSheet.pdf
R_CheatSheet.pdf
 
R교육1
R교육1R교육1
R교육1
 
Scala 3 enum for a terser Option Monad Algebraic Data Type
Scala 3 enum for a terser Option Monad Algebraic Data TypeScala 3 enum for a terser Option Monad Algebraic Data Type
Scala 3 enum for a terser Option Monad Algebraic Data Type
 
Class 31: Deanonymizing
Class 31: DeanonymizingClass 31: Deanonymizing
Class 31: Deanonymizing
 
Sample presentation slides template
Sample presentation slides templateSample presentation slides template
Sample presentation slides template
 
Programming in R
Programming in RProgramming in R
Programming in R
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and Profit
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
 
Structure Arrays
Structure ArraysStructure Arrays
Structure Arrays
 
Ggplot2 v3
Ggplot2 v3Ggplot2 v3
Ggplot2 v3
 

Dernier

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 

Dernier (20)

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 

Beginning-Scala-Options-Either-Try.pdf

  • 1. Uncovering the Power of Option, Either and Try Scala for Beginners Series Thursday, February 11, 2021
  • 2. Why Scala? ü Write clean, concise, powerful code — less boilerplate ü Fast development, prototyping ü Easier to write robust, fault-tolerant applications ü Wizards use it 2 Copyright (C) 2021 Murray Todd Williams
  • 3. Functional Programming …a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that map values to other values, rather than a sequence of imperative statements which update the running state of the program. Wikipedia int x = 0; while (data.ready()) { int a = data.next(); if (a > 0) x += a * a; } data.filter(_ > 0) .map(a => a * a) .sum 3 Copyright (C) 2021 Murray Todd Williams
  • 4. Quick advice for beginners: dump “var” var x: Int = 1 // 1 x += 3 // now 4 val x: Int = 1 x += 3 • error: reassignment to val Scala has two types of variable declarations: If you really want to learn Scala, don’t let yourself ever use var. It will seem incredibly hard at first. It may even seem impossible. (But it isn’t!) Eventually, your brain will make the paradigm shift. One hint: in some seemingly sticky situations, you’ll have to use recursion. It may seem weird, but don’t fight it. You can indeed evict the evil vars! 4 Copyright (C) 2021 Murray Todd Williams
  • 5. Writing robust, fault tolerant code Java’s NullPointerException is about as popular and notorious as the old BSOD. How does Scala avoid it? • All functions must return something (whatever type they declare) • Variables (vals) don’t get defined with uninitialized state • Functional programmers consider “unhappy paths” 5 Copyright (C) 2021 Murray Todd Williams
  • 6. Option[T] This is the easiest typeclass to understand: val name: Option[String] = Some("Murray") val name: Option[String] = None It lets you consider cases where you may or may not have a value. Consider looking up a name from a user database. What if the user ID can’t be found? def lookupName(id: String): Option[String] 6 Copyright (C) 2021 Murray Todd Williams
  • 7. Option is found throughout Scala library scala> val users = Map(1 -> "Alley", 2 -> "Sam") scala> users.get(1) val res0: Option[String] = Some(Alley) scala> users.get(3) val res1: Option[String] = None scala> users(3) java.util.NoSuchElementException: key not found: 3 at scala.collection.immutable.Map$Map2.apply(Map.scala:298) ... 32 elided 7 Copyright (C) 2021 Murray Todd Williams
  • 8. Try[T] This is next-most-natural way to handle things: val name: Try[String] = Success("Murray") val name: Try[String] = Failure(new Exception(…)) If you’re working with Java code or APIs where exceptions can be thrown (even simple IOExceptions) you can wrap it in a Try call. Try(db.lookup(name)) 8 Copyright (C) 2021 Murray Todd Williams
  • 9. Either[L,R] Strictly, an Either typeclass lets you have one of two types. def getAge(a: Int): Either[String,Int] = if (a < 16) Left("Renter is not old enought to drive.") else Right(a) scala> getAge(10) val res0: Either[String,Int] = Left(Renter is not old enought to drive.) scala> getAge(20) val res1: Either[String,Int] = Right(20) Conventionally, consider L to be the “unhappy path” and R to be the “happy path”. (Pneumonic: think happy as what’s “right”) 9 Copyright (C) 2021 Murray Todd Williams
  • 10. It can’t be too hard to use… I think I get the gist of this. 10 Copyright (C) 2021 Murray Todd Williams
  • 11. Let’s try to apply Option to a typical situation… scala> val users = Map(1 -> "Alley", 2 -> "Sam") scala> val greeting = if (users.contains(1)) { "Hello " + users(1) } val greeting: Any = Hello Alley scala> val greeting = if (users.contains(1)) { "Hello " + users.get(1) } else "Don't know" val greeting: String = Hello Some(Alley) scala> val greeting = if (users.contains(1)) { "Hello " + users(1) } else "Don't know" val greeting: String = Hello Alley scala> val greeting = if (users.contains(1)) { Some("Hello " + users(1)) } else None val greeting: Option[String] = Some(Hello Alley) 11 Copyright (C) 2021 Murray Todd Williams
  • 12. Let’s try something more realistic case class Contact(id: Int, name: String, phone: Option[String], email: Option[String], friendIds: List[Int]) { import Contact._ /* * Send an email to friends, inviting to join * @return List of successfully sent emails */ def inviteFriends: List[Int] = ??? } object Contact { def sendEmail(email: String): Boolean = ??? def dbLookup(id: Int): Try[Contact] = ??? } 12 Copyright (C) 2021 Murray Todd Williams
  • 13. Imperative (non-functional) approach def inviteFriends(friendIds: List[Int]): List[Int] = { var successes: List[Int] = List.empty for (id <- friendIds) { // lookup id from database // if you can find it and it’s defined, send an email // if it was successful, add the id to the successes list } successes } 13 Copyright (C) 2021 Murray Todd Williams
  • 14. Functional approach Approach: Start with a list of friend IDs to try End up with a list of friend IDs from successful emails Functional strategy: Apply an operation (lookup & send) to each item in the list, converting it into a success. friendIds.map(id => lookupAndSendWithSuccess(id)) This is sort of what we want. We really want to shorten the list to only have successful deliveries, but let’s not worry about that yet… 14 Copyright (C) 2021 Murray Todd Williams
  • 15. First “functional” iteration def inviteFriends: List[Int] = { val successes = friendIds.map { id => dbLookup(id) match { case Failure(_) => None case Success(friend) => { friend.email match { case Some(email) => if (sendEmail(email)) Some(id) else None case None => None } } } } ??? // success is now of type List[Option[Int]] } Happy Path 1 Happy Path 2 Happy Path 3 Unhappy 1 Unhappy 2 Unhappy 3 15 Copyright (C) 2021 Murray Todd Williams
  • 16. Yuck! Can I just keep doing imperative programming? Please! You said Scala was pretty, clean and succinct! 16 Copyright (C) 2021 Murray Todd Williams
  • 17. “Map” to the rescue! Option[T].map(f: T => U) becomes Option[U] Try[T].map(f: T => U) becomes Trt[U] Either[L,R].map(f: R => S) becomes Either[L,S] Let’s just write code snippets that focus on the ”happy paths” 17 Copyright (C) 2021 Murray Todd Williams
  • 18. “Map” to the rescue! friend.email match { case Some(email) => if (sendEmail(email)) Some(id) else None case None => None } friend.email.map(e => sendEmail(e)) friend.email.map(sendEmail) Let’s just write code snippets that focus on the ”happy paths” We get to think of e as a String (email) rather than an Option[String] To apply a function that only takes the one parameter, you can simplify by just supplying the function name. 18 Copyright (C) 2021 Murray Todd Williams
  • 19. Second “functional” iteration def inviteFriends: List[Int] = { val successes = friendIds.map { id => dbLookup(id).map { contact => contact.email.map { address => sendEmail(address) } } } ??? // successes is now of type List[Try[Option[Boolean]]] } Can I just keep doing imperative programming? This still doesn’t look clean! How do I work with a List of Try[Option[Boolean]] ?? 19 Copyright (C) 2021 Murray Todd Williams
  • 20. Boxes within boxes! (Turtles all the way down) Let’s start with 3 “safe” functions, each of which may or may not yield a successful transformation. f: A => Option[B] g: B => Option[C] h: C => Option[D] We want to apply these in order, like f(x).map(g).map(h), but we don’t want Option[Option[Option[D]]], we just want Option[D] 20 Copyright (C) 2021 Murray Todd Williams
  • 21. “FlatMap” to the rescue! scala> def getName(id: Int): Option[String] = users.get(id) def getName(id: Int): Option[String] scala> val id: Option[Int] = Some(2) val id: Option[Int] = Some(2) scala> id.flatMap(getName) val res3: Option[String] = Some(Sam) scala> val id: Option[Int] = Some(3) val id: Option[Int] = Some(3) scala> id.flatMap(getName) val res2: Option[String] = None 21 Copyright (C) 2021 Murray Todd Williams
  • 22. Think of Option, Try and Either as “Boxes” T T T Option[T] Some[T] or None Try[T] Success[T] or Failure[E] Either[S,T] Right[T] or Left[S] 22 Copyright (C) 2021 Murray Todd Williams
  • 23. All use “map” to apply functions to their contents. f(t) Option[T] Some[T] or None Try[T] Success[T] or Failure[E] Either[S,T] Right[T] or Left[S] f(t) f(t) (The functions are ignored if the boxes are empty) 23 Copyright (C) 2021 Murray Todd Williams
  • 24. All use “flatMap” for functions that would result in nested boxes. t => (The functions are ignored if the boxes are empty) f(t) f(t) flatMap only works if the boxes are the same, so Options inside Options 24 Copyright (C) 2021 Murray Todd Williams
  • 25. For multiple flatMap to work, keep the boxes the same! case class User(id: Int, email: Option[String]) def findUser(id: Int): Option[User] def sendEmail(email: User): Option[String] // None if email fails val sent = findUser(id).flatMap(_.email).flatMap(sendEmail) send will be of type Option[String] 25 Copyright (C) 2021 Murray Todd Williams
  • 26. Trick #1: Quick Convert Try[T] to Option[T] case class User(id: Int, email: Option[String]) def findUser(id: Int): Try[User] def sendEmail(user: User): Option[Int] // None if email fails val sent = findUser(id).toOption .flatMap(_.email).flatMap(sendEmail) 26 Copyright (C) 2021 Murray Todd Williams
  • 27. Remember how we mapped on List? T T T T T T List is just another type of box, except it doesn’t hold zero or one item of type T… … it holds zero or more items of type T. Looks more like an egg carton than a box! 27 Copyright (C) 2021 Murray Todd Williams
  • 28. Remember how we mapped on List? T T T T T T ”map” applies a function to each of the items If your function generates its own lists, flatMap “flattens” them! scala> val myList = List(3,2,1) val myList: List[Int] = List(3, 2, 1) scala> myList.map(x => List.fill(x)(x)) val res0: List[List[Int]] = List(List(3, 3, 3), List(2, 2), List(1)) scala> myList.flatMap(x => List.fill(x)(x)) val res1: List[Int] = List(3, 3, 3, 2, 2, 1) 28 Copyright (C) 2021 Murray Todd Williams
  • 29. Options are also Lists! Remember how we have to keep the ”boxes” the same for flatMap to work? Well, if you have an Option[T], it doubles as a List[T] with either zero (None) or one (Some(t)) elements! val friends: List[Contact] = friendIds.flatMap(id => dbLookup(id).toOption) val knownEmails: List[String] = friends.flatMap(_.email) 29 Copyright (C) 2021 Murray Todd Williams
  • 30. We’re almost done! def inviteFriends: List[Int] = friendIds .flatMap(id => dbLookup(id).toOption .flatMap(contact => contact.email) .filter(sendEmail).map(_ => id)) That’s not so bad, and I do have all the built-in safety stuff... but I’m still not sold. 30 Copyright (C) 2021 Murray Todd Williams
  • 31. Introducing For-comprehensions def inviteFriends: List[Int] = friendIds .flatMap(id => dbLookup(id).toOption .flatMap(contact => contact.email) .filter(sendEmail).map(_ => id)) def inviteFriends: List[Int] = { for { id <- friendIds contact <- dbLookup(id).toOption e <- contact.email status = sendEmail(e) if status } yield(id) } 31 Copyright (C) 2021 Murray Todd Williams
  • 32. Looking at the syntax in-depth These are flatMap operations <- A simple map (not flatMap) is represented by = ”if” statements translate to .filter statements Wow. Whatever type of Box we start with dictates the rest of the Boxes 32 Copyright (C) 2021 Murray Todd Williams def inviteFriends: List[Int] = { for { id <- friendIds contact <- dbLookup(id).toOption e <- contact.email status = sendEmail(e) if status } yield(id) }
  • 33. Summary • If you’re going to learn FP, start with banishing “var” • Everything is a composition of functions • Rather than iterating on lists, use “map” and “filter” and just transform them through your various stages • Handle potential ‘issues’ with Option, Try or Either • Operate on their contents by using ”map” and focusing on the happy path • FlatMap keeps you from boxing (nesting) your boxes • for-comprehensions create super-clean syntax for all of this Copyright (C) 2021 Murray Todd Williams 33
  • 34. Unveiling my Evil Master Plan… Copyright (C) 2021 Murray Todd Williams 34 All your base are belong to us
  • 35. You just learned about Monads A monad is a kind of typeclass that “boxes” any other type It has .map that applies functions to the contents of the boxes It has .flatMap for functions that create their own boxes in order to avoid nesting problems Option, Try, Either and Future are good examples of Monads They isolate “pure functions” from problematic contexts like asynchronous operations, exception handling, missing data, etc.