SlideShare a Scribd company logo
1 of 35
Download to read offline
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.

More Related Content

Similar to 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
 

Similar to 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
 

Recently uploaded

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.pptxHampshireHUG
 
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
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
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
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
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
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
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
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
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
 
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
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
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 slidevu2urc
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 

Recently uploaded (20)

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
 
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
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
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
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
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
 
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
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
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
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 

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.