SlideShare uma empresa Scribd logo
1 de 56
Baixar para ler offline
OPTION, EITHER, TRY
AND WHAT TO DO WITH CORNER CASES WHEN
THEY ARISE
KNOW YOUR LIBRARY MINI-SERIES
By /Michal Bigos @teliatko
KNOW YOUR LIBRARY - MINI SERIES
1. Hands-on with types from Scala library
2. DO's and DON'Ts
3. Intended for rookies, but Scala basic syntax assumed
4. Real world use cases
WHY NULL ISN'T AN OPTION
CONSIDER FOLLOWING CODE
String foo = request.params("foo")
if (foo != null) {
String bar = request.params("bar")
if (bar != null) {
doSomething(foo, bar)
} else {
throw new ApplicationException("Bar not found")
}
} else {
throw new ApplicationException("Foo not found")
}
WHY NULL ISN'T AN OPTION
WHAT'S WRONG WITH NULL
/* 1. Nobody knows about null, not even compiler */
String foo = request.params("foo")
/* 2. Annoying checking */
if (foo != null) {
String bar = request.params("bar")
// if (bar != null) {
/* 3. Danger of infamous NullPointerException,
everbody can forget some check */
doSomething(foo, bar)
// } else {
/* 4. Optionated detailed failures,
sometimes failure in the end is enough */
// throw new ApplicationException("Bar not found")
// }
} else {
/* 5. Design flaw, just original exception replacement */
throw new ApplicationException("Foo not found")
}
DEALING WITH NON-EXISTENCE
DIFFERENT APPROACHES COMPARED
Java relies on sad null
Groovy provides null-safe operator for accessing
properties
Clojure uses nilwhich is okay very often, but sometimes
it leads to an exception higher in call hierarchy
foo?.bar?.baz
GETTING RID OF NULL
NON-EXISTENCE SCALA WAY
Container with one or none element
sealed abstract class Option[A]
case class Some[+A](x: A) extends Option[A]
case object None extends Option[Nothing]
OPTION
1. States that value may or may not be present on type level
2. You are forced by the compiler to deal with it
3. No way to accidentally rely on presence of a value
4. Clearly documents an intention
OPTION IS MANDARORY!
OPTION
CREATING AN OPTION
Never do this
Rather use factory method on companion object
val certain = Some("Sun comes up")
val pitty = None
val nonSense = Some(null)
val muchBetter = Option(null) // Results to None
val certainAgain = Option("Sun comes up") // Some(Sun comes up)
OPTION
WORKING WITH OPTION AN OLD WAY
Don't do this (only in exceptional cases)
// Assume that
def param[String](name: String): Option[String] ...
val fooParam = request.param("foo")
val foo = if (fooParam.isDefined) {
fooParam.get // throws NoSuchElementException when None
} else {
"Default foo" // Default value
}
OPTION
PATTERN MATCHING
Don't do this (there's a better way)
val foo = request.param("foo") match {
case Some(value) => value
case None => "Default foo" // Default value
}
OPTION
PROVIDING A DEFAULT VALUE
Default value is by-name parameter. It's evaluated lazily.
// any long computation for default value
val foo = request.param("foo") getOrElse ("Default foo")
OPTION
TREATING IT FUNCTIONAL WAY
Think of Option as collection
It is biased towards Some
You can map, flatMapor compose Option(s) when it
contains value, i.e. it's Some
OPTION
EXAMPLE
Suppose following model and DAO
case class User(id: Int, name: String, age: Option[Int])
// In domain model, any optional value has to be expressed with Option
object UserDao {
def findById(id: Int): Option[User] = ...
// Id can always be incorrect, e.g. it's possible that user does not
exist already
}
OPTION
SIDE-EFFECTING
Use case: Printing the user name
// Suppose we have an userId from somewhere
val userOpt = UserDao.findById(userId)
// Just print user name
userOpt.foreach { user =>
println(user.name) // Nothing will be printed when None
} // Result is Unit (like void in Java)
// Or more concise
userOpt.foreach( user => println(user) )
// Or even more
userOpt.foreach( println(_) )
userOpt.foreach( println )
OPTION
MAP, FLATMAP & CO.
Use case: Extracting age
// Extracting age
val ageOpt = UserDao.findById(userId).map( _.age )
// Returns Option[Option[Int]]
val ageOpt = UserDao.findById(userId).map( _.age.map( age => age ) )
// ReturnsOption[Option[Int]] too
// Extracting age, take 2
val ageOpt = UserDao.findById(userId).flatMap( _.age.map( age => age )
)
// Returns Option[Int]
OPTION
FOR COMPREHENSIONS
Same use case as before
Usage in left side of generator
// Extracting age, take 3
val ageOpt = for {
user <- UserDao.findById(userId)
age <- user.age
} yield age // Returns Option[Int]
// Extracting age, take 3
val ageOpt = for {
User(_, Some(age)) <- UserDao.findById(userId)
} yield age // Returns Option[Int]
OPTION
COMPOSING TO LIST
Use case: Pretty-print of user
Different notation
Both prints
Rule of thumb: wrap all mandatory fields with Option and
then concatenate with optional ones
def prettyPrint(user: User) =
List(Option(user.name), user.age).mkString(", ")
def prettyPrint(user: User) =
(Option(user.name) ++ user.age).mkString(", ")
val foo = User("Foo", Some(10))
val bar = User("Bar", None)
prettyPrint(foo) // Prints "Foo, 10"
prettyPrint(bar) // Prints "Bar"
OPTION
CHAINING
Use case: Fetching or creating the user
More appropriate, when Useris desired directly
object UserDao {
// New method
def createUser: User
}
val userOpt = UserDao.findById(userId) orElse Some(UserDao.create)
val user = UserDao.findById(userId) getOrElse UserDao.create
OPTION
MORE TO EXPLORE
sealed abstract class Option[A] {
def fold[B](ifEmpty: Ó B)(f: (A) Ó B): B
def filter(p: (A) Ó Boolean): Option[A]
def exists(p: (A) Ó Boolean): Boolean
...
}
IS OPTION APPROPRIATE?
Consider following piece of code
When something went wrong, cause is lost forever
case class UserFilter(name: String, age: Int)
def parseFilter(input: String): Option[UserFilter] = {
for {
name <- parseName(input)
age <- parseAge(input)
} yield UserFilter(name, age)
}
// Suppose that parseName and parseAge throws FilterException
def parseFilter(input: String): Option[UserFilter]
throws FilterException { ... }
// caller side
val filter = try {
parseFilter(input)
} catch {
case e: FilterException => whatToDoInTheMiddleOfTheCode(e)
}
Exception doesn't help much. It only introduces overhead
INTRODUCING EITHER
Container with disjoint types.
sealed abstract class Either[+L, +R]
case class Left[+L, +R](a: L) extends Either[L, R]
case class Right[+L, +R](b: R) extends Either[L, R]
EITHER
1. States that value is either Left[L]or Right[R], but
never both.
2. No explicit sematics, but by convention Left[L]
represents corner case and Right[R]desired one.
3. Functional way of dealing with alternatives, consider:
4. Again, it clearly documents an intention
def doSomething(): Int throws SomeException
// what is this saying? two possible outcomes
def doSomething(): Either[SomeException, Int]
// more functional only one return value
EITHER IS NOT BIASED
EITHER
CREATING EITHER
There is no Either(...)factory method on companion
object.
def parseAge(input: String): Either[String, Int] = {
try {
Right(input.toInt)
} catch {
case nfe: NumberFormatException => Left("Unable to parse age")
}
}
EITHER
WORKING AN OLD WAY AGAIN
Don't do this (only in exceptional cases)
def parseFilter(input: String): Either[String, ExtendedFilter] = {
val name = parseName(input)
if (name.isRight) {
val age = parseAge(input)
if (age.isRight) {
Right(UserFilter(time, rating))
} else age
} else name
}
EITHER
PATTERN MATCHING
Don't do this (there's a better way)
def parseFilter(input: String): Either[String, ExtendedFilter] = {
parseName(input) match {
case Right(name) => parseAge(input) match {
case Right(age) => UserFilter(name, age)
case error: Left[_] => error
}
case error: Left[_] => error
}
}
EITHER
PROJECTIONS
You cannot directly use instance of Eitheras collection.
It's unbiased, you have to define what is your prefered side.
Working on success, only 1st error is returned.
either.rightreturns RightProjection
def parseFilter(input: String): Either[String, UserFilter] = {
for {
name <- parseName(input).right
age <- parseAge(input).right
} yield Right(UserFilter(name, age))
}
EITHER
PROJECTIONS, TAKE 2
Working on both sides, all errors are collected.
either.leftreturns LeftProjection
def parseFilter(input: String): Either[List[String], UserFilter] = {
val name = parseName(input)
val age = parseAge(input)
val errors = name.left.toOption ++ age.left.toOption
if (errors.isEmpty) {
Right(UserFilter(name.right.get, age.right.get))
} else {
Left(errors)
}
}
EITHER
PROJECTIONS, TAKE 3
Both projection are biased wrappers for Either
You can use map, flatMapon them too, but beware
This is inconsistent in regdard to other collections.
val rightThing = Right(User("Foo", Some(10)))
val projection = rightThing.right // Type is RightProjection[User]
val rightThingAgain = projection.map ( _.name )
// Isn't RightProjection[User] but Right[User]
EITHER
PROJECTIONS, TAKE 4
It can lead to problems with for comprehensions.
This won't compile.
After removing syntactic suggar, we get
We need projection again
for {
name <- parseName(input).right
bigName <- name.capitalize
} yield bigName
parseName(input).right.map { name =>
val bigName = name.capitalize
(bigName)
}.map { case (x) => x } // Map is not member of Either
for {
name <- parseName(input).right
bigName <- Right(name.capitalize).right
} yield bigName
EITHER
FOLDING
Allows transforming the Eitherregardless if it's Rightor
Lefton the same type
Accepts functions, both are evaluated lazily. Result from both
functions has same type.
// Once upon a time in controller
parseFilter(input).fold(
// Bad (Left) side transformation to HttpResponse
errors => BadRequest("Error in filter")
// Good (Right) side transformation to HttpResponse
filter => Ok(doSomethingWith(filter))
)
EITHER
MORE TO EXPLORE
sealed abstract class Either[+A, +B] {
def joinLeft[A1 >: A, B1 >: B, C](implicit ev: <:<[A1, Either[C, B1
]]): Either[C, B1]
def joinRight[A1 >: A, B1 >: B, C](implicit ev: <:<[B1, Either[A1,
C]]): Either[A1, C]
def swap: Product with Serializable with Either[B, A]
}
THROWING AND CATCHING EXCEPTIONS
SOMETIMES THINGS REALLY GO WRONG
You can use classic try/catch/finallyconstruct
def parseAge(input: String): Either[String, Int] = {
try {
Right(input.toInt)
} catch {
case nfe: NumberFormatException => Left("Unable to parse age")
}
}
THROWING AND CATCHING EXCEPTIONS
SOMETIMES THINGS REALLY GO WRONG, TAKE 2
But, it's try/catch/finallyon steroids thanks to pattern
matching
try {
someHorribleCodeHere()
} catch {
// Catching multiple types
case e @ (_: IOException | _: NastyExpception) => cleanUpMess()
// Catching exceptions by message
case e : AnotherNastyException
if e.getMessage contains "Wrong again" => cleanUpMess()
// Catching all exceptions
case e: Exception => cleanUpMess()
}
THROWING AND CATCHING EXCEPTIONS
SOMETIMES THINGS REALLY GO WRONG, TAKE 3
It's powerful, but beware
Never do this!
Prefered approach of catching all
try {
someHorribleCodeHere()
} catch {
// This will match scala.util.control.ControlThrowable too
case _ => cleanUpMess()
}
try {
someHorribleCodeHere()
} catch {
// This will match scala.util.control.ControlThrowable too
case t: ControlThrowable => throw t
case _ => cleanUpMess()
}
WHAT'S WRONG WITH EXCEPTIONS
1. Referential transparency - is there a value the RHS can be
replaced with? No.
2. Code base can become ugly
3. Exceptions do not go well with concurrency
val something = throw new IllegalArgumentException("Foo is missing")
// Result type is Nothing
SHOULD I THROW AN EXCEPTION?
No, there is better approach
EXCEPTION HANDLING FUNCTIONAL WAY
Please welcome
import scala.util.control._
and
Collection of Throwableor value
sealed trait Try[A]
case class Failure[A](e: Throwable) extends Try[A]
case class Success[A](value: A) extends Try[A]
TRY
1. States that computation may be Success[T]or may be
Failure[T]ending with Throwableon type level
2. Similar to Option, it's Successbiased
3. It's try/catchwithout boilerplate
4. Again it clearly documents what is happening
TRY
LIKE OPTION
All the operations from Optionare present
sealed abstract class Try[+T] {
// Throws exception of Failure or return value of Success
def get: T
// Old way checks
def isFailure: Boolean
def isSuccess: Boolean
// map, flatMap & Co.
def map[U](f: (T) Ó U): Try[U]
def flatMap[U](f: (T) Ó Try[U]): Try[U]
// Side effecting
def foreach[U](f: (T) Ó U): Unit
// Default value
def getOrElse[U >: T](default: Ó U): U
// Chaining
def orElse[U >: T](default: Ó Try[U]): Try[U]
}
TRY
BUT THERE IS MORE
Assume that
Recovering from a Failure
Converting to Option
def parseAge(input: String): Try[Int] = Try ( input.toInt )
val age = parseAge("not a number") recover {
case e: NumberFormatException => 0 // Default value
case _ => -1 // Another default value
} // Result is always Success
val ageOpt = age.toOption
// Will be Some if Success, None if Failure
SCALA.UTIL.CONTROL._
1. Utility methods for common exception handling patterns
2. Less boiler plate than try/catch/finally
SCALA.UTIL.CONTROL._
CATCHING AN EXCEPTION
It returns Catch[T]
catching(classOf[NumberFormatException]) {
input.toInt
} // Returns Catch[Int]
SCALA.UTIL.CONTROL._
CONVERTING
Converting to `Option
Converting to Either
Converting to Try
catching(classOf[NumberFormatException]).opt {
input.toInt
} // Returns Option[Int]
failing(classOf[NumberFormatException]) {
input.toInt
} // Returns Option[Int]
catching(classOf[NumberFormatException]).either {
input.toInt
} // Returns Either[Throwable, Int]
catching(classOf[NumberFormatException]).withTry {
input.toInt
} // Returns Try[Int]
SCALA.UTIL.CONTROL._
SIDE-EFFECTING
ignoring(classOf[NumberFormatException]) {
println(input.toInt)
} // Returns Catch[Unit]
SCALA.UTIL.CONTROL._
CATCHING NON-FATAL EXCEPTIONS
What are non-fatal exceptions?
All instead of:
VirtualMachineError, ThreadDeath,
InterruptedException, LinkageError,
ControlThrowable, NotImplementedError
nonFatalCatch {
println(input.toInt)
}
SCALA.UTIL.CONTROL._
PROVIDING DEFAULT VALUE
val age = failAsValue(classOf[NumberFormatException])(0) {
input.toInt
}
SCALA.UTIL.CONTROL._
WHAT ABOUT FINALLY
With catch logic
No catch logic
catching(classOf[NumberFormatException]).andFinally {
println("Age parsed somehow")
}.apply {
input.toInt
}
ultimately(println("Age parsed somehow")) {
input.toInt
}
SCALA.UTIL.CONTROL._
There's more to cover and explore,
please check out the .Scala documentation
THANKS FOR YOUR ATTENTION

Mais conteúdo relacionado

Mais procurados

Java 5 New Feature
Java 5 New FeatureJava 5 New Feature
Java 5 New Featurexcoda
 
Swift Programming Language
Swift Programming LanguageSwift Programming Language
Swift Programming LanguageGiuseppe Arici
 
Acciones para AmigoBot
Acciones para AmigoBotAcciones para AmigoBot
Acciones para AmigoBotjhonsoomelol
 
Thumbtack Expertise Days # 5 - Javaz
Thumbtack Expertise Days # 5 - JavazThumbtack Expertise Days # 5 - Javaz
Thumbtack Expertise Days # 5 - JavazAlexey Remnev
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Arthur Puthin
 
Type Classes in Scala and Haskell
Type Classes in Scala and HaskellType Classes in Scala and Haskell
Type Classes in Scala and HaskellHermann Hueck
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftMichele Titolo
 
Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick referenceilesh raval
 
Peyton jones-2011-type classes
Peyton jones-2011-type classesPeyton jones-2011-type classes
Peyton jones-2011-type classesTakayuki Muranushi
 
Peyton jones-2009-fun with-type_functions-slide
Peyton jones-2009-fun with-type_functions-slidePeyton jones-2009-fun with-type_functions-slide
Peyton jones-2009-fun with-type_functions-slideTakayuki Muranushi
 
JAVA Tutorial- Do's and Don'ts of Java programming
JAVA Tutorial- Do's and Don'ts of Java programmingJAVA Tutorial- Do's and Don'ts of Java programming
JAVA Tutorial- Do's and Don'ts of Java programmingKeshav Kumar
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Hermann Hueck
 
2 kotlin vs. java: what java has that kotlin does not
2  kotlin vs. java: what java has that kotlin does not2  kotlin vs. java: what java has that kotlin does not
2 kotlin vs. java: what java has that kotlin does notSergey Bandysik
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsPatchSpace Ltd
 
Google collections api an introduction
Google collections api   an introductionGoogle collections api   an introduction
Google collections api an introductiongosain20
 

Mais procurados (20)

Java 5 New Feature
Java 5 New FeatureJava 5 New Feature
Java 5 New Feature
 
Swift Programming Language
Swift Programming LanguageSwift Programming Language
Swift Programming Language
 
Acciones para AmigoBot
Acciones para AmigoBotAcciones para AmigoBot
Acciones para AmigoBot
 
Thumbtack Expertise Days # 5 - Javaz
Thumbtack Expertise Days # 5 - JavazThumbtack Expertise Days # 5 - Javaz
Thumbtack Expertise Days # 5 - Javaz
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...
 
Type Classes in Scala and Haskell
Type Classes in Scala and HaskellType Classes in Scala and Haskell
Type Classes in Scala and Haskell
 
JAVA OOP
JAVA OOPJAVA OOP
JAVA OOP
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in Swift
 
Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick reference
 
Peyton jones-2011-type classes
Peyton jones-2011-type classesPeyton jones-2011-type classes
Peyton jones-2011-type classes
 
Peyton jones-2009-fun with-type_functions-slide
Peyton jones-2009-fun with-type_functions-slidePeyton jones-2009-fun with-type_functions-slide
Peyton jones-2009-fun with-type_functions-slide
 
JAVA Tutorial- Do's and Don'ts of Java programming
JAVA Tutorial- Do's and Don'ts of Java programmingJAVA Tutorial- Do's and Don'ts of Java programming
JAVA Tutorial- Do's and Don'ts of Java programming
 
Scala Paradigms
Scala ParadigmsScala Paradigms
Scala Paradigms
 
Erjang - A JVM-based Erlang VM
Erjang - A JVM-based Erlang VMErjang - A JVM-based Erlang VM
Erjang - A JVM-based Erlang VM
 
Python
PythonPython
Python
 
Cheat Sheet java
Cheat Sheet javaCheat Sheet java
Cheat Sheet java
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
2 kotlin vs. java: what java has that kotlin does not
2  kotlin vs. java: what java has that kotlin does not2  kotlin vs. java: what java has that kotlin does not
2 kotlin vs. java: what java has that kotlin does not
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
 
Google collections api an introduction
Google collections api   an introductionGoogle collections api   an introduction
Google collections api an introduction
 

Semelhante a Option, Either, Try and what to do with corner cases when they arise

Stuff you didn't know about action script
Stuff you didn't know about action scriptStuff you didn't know about action script
Stuff you didn't know about action scriptChristophe Herreman
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2Hang Zhao
 
A Brief Intro to Scala
A Brief Intro to ScalaA Brief Intro to Scala
A Brief Intro to ScalaTim Underwood
 
No excuses, switch to kotlin
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlinThijs Suijten
 
Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Cody Engel
 
Bologna Developer Zone - About Kotlin
Bologna Developer Zone - About KotlinBologna Developer Zone - About Kotlin
Bologna Developer Zone - About KotlinMarco Vasapollo
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecLoïc Descotte
 
Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner codeMite Mitreski
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Omar Miatello
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming iiPrashant Kalkar
 
Java Generics for Dummies
Java Generics for DummiesJava Generics for Dummies
Java Generics for Dummiesknutmork
 

Semelhante a Option, Either, Try and what to do with corner cases when they arise (20)

Stuff you didn't know about action script
Stuff you didn't know about action scriptStuff you didn't know about action script
Stuff you didn't know about action script
 
Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
A Brief Intro to Scala
A Brief Intro to ScalaA Brief Intro to Scala
A Brief Intro to Scala
 
Exploring ES6
Exploring ES6Exploring ES6
Exploring ES6
 
No excuses, switch to kotlin
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlin
 
Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)
 
ES6 and BEYOND
ES6 and BEYONDES6 and BEYOND
ES6 and BEYOND
 
Bologna Developer Zone - About Kotlin
Bologna Developer Zone - About KotlinBologna Developer Zone - About Kotlin
Bologna Developer Zone - About Kotlin
 
Scala for curious
Scala for curiousScala for curious
Scala for curious
 
DITEC - Programming with Java
DITEC - Programming with JavaDITEC - Programming with Java
DITEC - Programming with Java
 
Kotlin
KotlinKotlin
Kotlin
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar Prokopec
 
Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner code
 
Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03Android & Kotlin - The code awakens #03
Android & Kotlin - The code awakens #03
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Java Generics for Dummies
Java Generics for DummiesJava Generics for Dummies
Java Generics for Dummies
 
Txjs
TxjsTxjs
Txjs
 

Mais de Michal Bigos

All About ... Functions
All About ... FunctionsAll About ... Functions
All About ... FunctionsMichal Bigos
 
Scala eXchange 2013 Report
Scala eXchange 2013 ReportScala eXchange 2013 Report
Scala eXchange 2013 ReportMichal Bigos
 
Functional Domain Modeling
Functional Domain ModelingFunctional Domain Modeling
Functional Domain ModelingMichal Bigos
 
Dependency injection in scala
Dependency injection in scalaDependency injection in scala
Dependency injection in scalaMichal Bigos
 
Integration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBIntegration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBMichal Bigos
 

Mais de Michal Bigos (6)

All About ... Functions
All About ... FunctionsAll About ... Functions
All About ... Functions
 
Scala eXchange 2013 Report
Scala eXchange 2013 ReportScala eXchange 2013 Report
Scala eXchange 2013 Report
 
Functional Domain Modeling
Functional Domain ModelingFunctional Domain Modeling
Functional Domain Modeling
 
SBT Crash Course
SBT Crash CourseSBT Crash Course
SBT Crash Course
 
Dependency injection in scala
Dependency injection in scalaDependency injection in scala
Dependency injection in scala
 
Integration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBIntegration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDB
 

Último

Activity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdfActivity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdfciinovamais
 
Class 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdfClass 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdfAyushMahapatra5
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.christianmathematics
 
Making and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdfMaking and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdfChris Hunter
 
Unit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptxUnit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptxVishalSingh1417
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeThiyagu K
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxAreebaZafar22
 
Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactPECB
 
Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104misteraugie
 
ICT role in 21st century education and it's challenges.
ICT role in 21st century education and it's challenges.ICT role in 21st century education and it's challenges.
ICT role in 21st century education and it's challenges.MaryamAhmad92
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdfQucHHunhnh
 
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...christianmathematics
 
Unit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxUnit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxVishalSingh1417
 
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptxMaritesTamaniVerdade
 
Z Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphZ Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphThiyagu K
 
Seal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxSeal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxnegromaestrong
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsMebane Rash
 
Mixin Classes in Odoo 17 How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17  How to Extend Models Using Mixin ClassesMixin Classes in Odoo 17  How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17 How to Extend Models Using Mixin ClassesCeline George
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhikauryashika82
 

Último (20)

Activity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdfActivity 01 - Artificial Culture (1).pdf
Activity 01 - Artificial Culture (1).pdf
 
Class 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdfClass 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdf
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.
 
Making and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdfMaking and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdf
 
Unit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptxUnit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptx
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and Mode
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 
Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global Impact
 
Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104
 
ICT role in 21st century education and it's challenges.
ICT role in 21st century education and it's challenges.ICT role in 21st century education and it's challenges.
ICT role in 21st century education and it's challenges.
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdf
 
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
 
Unit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxUnit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptx
 
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
 
Z Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphZ Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot Graph
 
Seal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxSeal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptx
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan Fellows
 
Mixin Classes in Odoo 17 How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17  How to Extend Models Using Mixin ClassesMixin Classes in Odoo 17  How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17 How to Extend Models Using Mixin Classes
 
Asian American Pacific Islander Month DDSD 2024.pptx
Asian American Pacific Islander Month DDSD 2024.pptxAsian American Pacific Islander Month DDSD 2024.pptx
Asian American Pacific Islander Month DDSD 2024.pptx
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
 

Option, Either, Try and what to do with corner cases when they arise

  • 1. OPTION, EITHER, TRY AND WHAT TO DO WITH CORNER CASES WHEN THEY ARISE KNOW YOUR LIBRARY MINI-SERIES By /Michal Bigos @teliatko
  • 2. KNOW YOUR LIBRARY - MINI SERIES 1. Hands-on with types from Scala library 2. DO's and DON'Ts 3. Intended for rookies, but Scala basic syntax assumed 4. Real world use cases
  • 3. WHY NULL ISN'T AN OPTION CONSIDER FOLLOWING CODE String foo = request.params("foo") if (foo != null) { String bar = request.params("bar") if (bar != null) { doSomething(foo, bar) } else { throw new ApplicationException("Bar not found") } } else { throw new ApplicationException("Foo not found") }
  • 4. WHY NULL ISN'T AN OPTION WHAT'S WRONG WITH NULL /* 1. Nobody knows about null, not even compiler */ String foo = request.params("foo") /* 2. Annoying checking */ if (foo != null) { String bar = request.params("bar") // if (bar != null) { /* 3. Danger of infamous NullPointerException, everbody can forget some check */ doSomething(foo, bar) // } else { /* 4. Optionated detailed failures, sometimes failure in the end is enough */ // throw new ApplicationException("Bar not found") // } } else { /* 5. Design flaw, just original exception replacement */ throw new ApplicationException("Foo not found") }
  • 5. DEALING WITH NON-EXISTENCE DIFFERENT APPROACHES COMPARED Java relies on sad null Groovy provides null-safe operator for accessing properties Clojure uses nilwhich is okay very often, but sometimes it leads to an exception higher in call hierarchy foo?.bar?.baz
  • 6. GETTING RID OF NULL NON-EXISTENCE SCALA WAY Container with one or none element sealed abstract class Option[A] case class Some[+A](x: A) extends Option[A] case object None extends Option[Nothing]
  • 7. OPTION 1. States that value may or may not be present on type level 2. You are forced by the compiler to deal with it 3. No way to accidentally rely on presence of a value 4. Clearly documents an intention
  • 9. OPTION CREATING AN OPTION Never do this Rather use factory method on companion object val certain = Some("Sun comes up") val pitty = None val nonSense = Some(null) val muchBetter = Option(null) // Results to None val certainAgain = Option("Sun comes up") // Some(Sun comes up)
  • 10. OPTION WORKING WITH OPTION AN OLD WAY Don't do this (only in exceptional cases) // Assume that def param[String](name: String): Option[String] ... val fooParam = request.param("foo") val foo = if (fooParam.isDefined) { fooParam.get // throws NoSuchElementException when None } else { "Default foo" // Default value }
  • 11. OPTION PATTERN MATCHING Don't do this (there's a better way) val foo = request.param("foo") match { case Some(value) => value case None => "Default foo" // Default value }
  • 12. OPTION PROVIDING A DEFAULT VALUE Default value is by-name parameter. It's evaluated lazily. // any long computation for default value val foo = request.param("foo") getOrElse ("Default foo")
  • 13. OPTION TREATING IT FUNCTIONAL WAY Think of Option as collection It is biased towards Some You can map, flatMapor compose Option(s) when it contains value, i.e. it's Some
  • 14. OPTION EXAMPLE Suppose following model and DAO case class User(id: Int, name: String, age: Option[Int]) // In domain model, any optional value has to be expressed with Option object UserDao { def findById(id: Int): Option[User] = ... // Id can always be incorrect, e.g. it's possible that user does not exist already }
  • 15. OPTION SIDE-EFFECTING Use case: Printing the user name // Suppose we have an userId from somewhere val userOpt = UserDao.findById(userId) // Just print user name userOpt.foreach { user => println(user.name) // Nothing will be printed when None } // Result is Unit (like void in Java) // Or more concise userOpt.foreach( user => println(user) ) // Or even more userOpt.foreach( println(_) ) userOpt.foreach( println )
  • 16. OPTION MAP, FLATMAP & CO. Use case: Extracting age // Extracting age val ageOpt = UserDao.findById(userId).map( _.age ) // Returns Option[Option[Int]] val ageOpt = UserDao.findById(userId).map( _.age.map( age => age ) ) // ReturnsOption[Option[Int]] too // Extracting age, take 2 val ageOpt = UserDao.findById(userId).flatMap( _.age.map( age => age ) ) // Returns Option[Int]
  • 17. OPTION FOR COMPREHENSIONS Same use case as before Usage in left side of generator // Extracting age, take 3 val ageOpt = for { user <- UserDao.findById(userId) age <- user.age } yield age // Returns Option[Int] // Extracting age, take 3 val ageOpt = for { User(_, Some(age)) <- UserDao.findById(userId) } yield age // Returns Option[Int]
  • 18. OPTION COMPOSING TO LIST Use case: Pretty-print of user Different notation Both prints Rule of thumb: wrap all mandatory fields with Option and then concatenate with optional ones def prettyPrint(user: User) = List(Option(user.name), user.age).mkString(", ") def prettyPrint(user: User) = (Option(user.name) ++ user.age).mkString(", ") val foo = User("Foo", Some(10)) val bar = User("Bar", None) prettyPrint(foo) // Prints "Foo, 10" prettyPrint(bar) // Prints "Bar"
  • 19.
  • 20. OPTION CHAINING Use case: Fetching or creating the user More appropriate, when Useris desired directly object UserDao { // New method def createUser: User } val userOpt = UserDao.findById(userId) orElse Some(UserDao.create) val user = UserDao.findById(userId) getOrElse UserDao.create
  • 21. OPTION MORE TO EXPLORE sealed abstract class Option[A] { def fold[B](ifEmpty: Ó B)(f: (A) Ó B): B def filter(p: (A) Ó Boolean): Option[A] def exists(p: (A) Ó Boolean): Boolean ... }
  • 22. IS OPTION APPROPRIATE? Consider following piece of code When something went wrong, cause is lost forever case class UserFilter(name: String, age: Int) def parseFilter(input: String): Option[UserFilter] = { for { name <- parseName(input) age <- parseAge(input) } yield UserFilter(name, age) } // Suppose that parseName and parseAge throws FilterException def parseFilter(input: String): Option[UserFilter] throws FilterException { ... } // caller side val filter = try { parseFilter(input) } catch { case e: FilterException => whatToDoInTheMiddleOfTheCode(e) }
  • 23. Exception doesn't help much. It only introduces overhead
  • 24. INTRODUCING EITHER Container with disjoint types. sealed abstract class Either[+L, +R] case class Left[+L, +R](a: L) extends Either[L, R] case class Right[+L, +R](b: R) extends Either[L, R]
  • 25. EITHER 1. States that value is either Left[L]or Right[R], but never both. 2. No explicit sematics, but by convention Left[L] represents corner case and Right[R]desired one. 3. Functional way of dealing with alternatives, consider: 4. Again, it clearly documents an intention def doSomething(): Int throws SomeException // what is this saying? two possible outcomes def doSomething(): Either[SomeException, Int] // more functional only one return value
  • 26. EITHER IS NOT BIASED
  • 27. EITHER CREATING EITHER There is no Either(...)factory method on companion object. def parseAge(input: String): Either[String, Int] = { try { Right(input.toInt) } catch { case nfe: NumberFormatException => Left("Unable to parse age") } }
  • 28. EITHER WORKING AN OLD WAY AGAIN Don't do this (only in exceptional cases) def parseFilter(input: String): Either[String, ExtendedFilter] = { val name = parseName(input) if (name.isRight) { val age = parseAge(input) if (age.isRight) { Right(UserFilter(time, rating)) } else age } else name }
  • 29. EITHER PATTERN MATCHING Don't do this (there's a better way) def parseFilter(input: String): Either[String, ExtendedFilter] = { parseName(input) match { case Right(name) => parseAge(input) match { case Right(age) => UserFilter(name, age) case error: Left[_] => error } case error: Left[_] => error } }
  • 30. EITHER PROJECTIONS You cannot directly use instance of Eitheras collection. It's unbiased, you have to define what is your prefered side. Working on success, only 1st error is returned. either.rightreturns RightProjection def parseFilter(input: String): Either[String, UserFilter] = { for { name <- parseName(input).right age <- parseAge(input).right } yield Right(UserFilter(name, age)) }
  • 31. EITHER PROJECTIONS, TAKE 2 Working on both sides, all errors are collected. either.leftreturns LeftProjection def parseFilter(input: String): Either[List[String], UserFilter] = { val name = parseName(input) val age = parseAge(input) val errors = name.left.toOption ++ age.left.toOption if (errors.isEmpty) { Right(UserFilter(name.right.get, age.right.get)) } else { Left(errors) } }
  • 32. EITHER PROJECTIONS, TAKE 3 Both projection are biased wrappers for Either You can use map, flatMapon them too, but beware This is inconsistent in regdard to other collections. val rightThing = Right(User("Foo", Some(10))) val projection = rightThing.right // Type is RightProjection[User] val rightThingAgain = projection.map ( _.name ) // Isn't RightProjection[User] but Right[User]
  • 33. EITHER PROJECTIONS, TAKE 4 It can lead to problems with for comprehensions. This won't compile. After removing syntactic suggar, we get We need projection again for { name <- parseName(input).right bigName <- name.capitalize } yield bigName parseName(input).right.map { name => val bigName = name.capitalize (bigName) }.map { case (x) => x } // Map is not member of Either
  • 34. for { name <- parseName(input).right bigName <- Right(name.capitalize).right } yield bigName
  • 35. EITHER FOLDING Allows transforming the Eitherregardless if it's Rightor Lefton the same type Accepts functions, both are evaluated lazily. Result from both functions has same type. // Once upon a time in controller parseFilter(input).fold( // Bad (Left) side transformation to HttpResponse errors => BadRequest("Error in filter") // Good (Right) side transformation to HttpResponse filter => Ok(doSomethingWith(filter)) )
  • 36. EITHER MORE TO EXPLORE sealed abstract class Either[+A, +B] { def joinLeft[A1 >: A, B1 >: B, C](implicit ev: <:<[A1, Either[C, B1 ]]): Either[C, B1] def joinRight[A1 >: A, B1 >: B, C](implicit ev: <:<[B1, Either[A1, C]]): Either[A1, C] def swap: Product with Serializable with Either[B, A] }
  • 37. THROWING AND CATCHING EXCEPTIONS SOMETIMES THINGS REALLY GO WRONG You can use classic try/catch/finallyconstruct def parseAge(input: String): Either[String, Int] = { try { Right(input.toInt) } catch { case nfe: NumberFormatException => Left("Unable to parse age") } }
  • 38. THROWING AND CATCHING EXCEPTIONS SOMETIMES THINGS REALLY GO WRONG, TAKE 2 But, it's try/catch/finallyon steroids thanks to pattern matching try { someHorribleCodeHere() } catch { // Catching multiple types case e @ (_: IOException | _: NastyExpception) => cleanUpMess() // Catching exceptions by message case e : AnotherNastyException if e.getMessage contains "Wrong again" => cleanUpMess() // Catching all exceptions case e: Exception => cleanUpMess() }
  • 39. THROWING AND CATCHING EXCEPTIONS SOMETIMES THINGS REALLY GO WRONG, TAKE 3 It's powerful, but beware Never do this! Prefered approach of catching all try { someHorribleCodeHere() } catch { // This will match scala.util.control.ControlThrowable too case _ => cleanUpMess() } try { someHorribleCodeHere() } catch { // This will match scala.util.control.ControlThrowable too case t: ControlThrowable => throw t case _ => cleanUpMess() }
  • 40.
  • 41. WHAT'S WRONG WITH EXCEPTIONS 1. Referential transparency - is there a value the RHS can be replaced with? No. 2. Code base can become ugly 3. Exceptions do not go well with concurrency val something = throw new IllegalArgumentException("Foo is missing") // Result type is Nothing
  • 42. SHOULD I THROW AN EXCEPTION? No, there is better approach
  • 43. EXCEPTION HANDLING FUNCTIONAL WAY Please welcome import scala.util.control._ and Collection of Throwableor value sealed trait Try[A] case class Failure[A](e: Throwable) extends Try[A] case class Success[A](value: A) extends Try[A]
  • 44. TRY 1. States that computation may be Success[T]or may be Failure[T]ending with Throwableon type level 2. Similar to Option, it's Successbiased 3. It's try/catchwithout boilerplate 4. Again it clearly documents what is happening
  • 45. TRY LIKE OPTION All the operations from Optionare present sealed abstract class Try[+T] { // Throws exception of Failure or return value of Success def get: T // Old way checks def isFailure: Boolean def isSuccess: Boolean // map, flatMap & Co. def map[U](f: (T) Ó U): Try[U] def flatMap[U](f: (T) Ó Try[U]): Try[U] // Side effecting def foreach[U](f: (T) Ó U): Unit // Default value def getOrElse[U >: T](default: Ó U): U // Chaining def orElse[U >: T](default: Ó Try[U]): Try[U] }
  • 46. TRY BUT THERE IS MORE Assume that Recovering from a Failure Converting to Option def parseAge(input: String): Try[Int] = Try ( input.toInt ) val age = parseAge("not a number") recover { case e: NumberFormatException => 0 // Default value case _ => -1 // Another default value } // Result is always Success val ageOpt = age.toOption // Will be Some if Success, None if Failure
  • 47. SCALA.UTIL.CONTROL._ 1. Utility methods for common exception handling patterns 2. Less boiler plate than try/catch/finally
  • 48. SCALA.UTIL.CONTROL._ CATCHING AN EXCEPTION It returns Catch[T] catching(classOf[NumberFormatException]) { input.toInt } // Returns Catch[Int]
  • 49. SCALA.UTIL.CONTROL._ CONVERTING Converting to `Option Converting to Either Converting to Try catching(classOf[NumberFormatException]).opt { input.toInt } // Returns Option[Int] failing(classOf[NumberFormatException]) { input.toInt } // Returns Option[Int] catching(classOf[NumberFormatException]).either { input.toInt } // Returns Either[Throwable, Int] catching(classOf[NumberFormatException]).withTry { input.toInt } // Returns Try[Int]
  • 50.
  • 52. SCALA.UTIL.CONTROL._ CATCHING NON-FATAL EXCEPTIONS What are non-fatal exceptions? All instead of: VirtualMachineError, ThreadDeath, InterruptedException, LinkageError, ControlThrowable, NotImplementedError nonFatalCatch { println(input.toInt) }
  • 53. SCALA.UTIL.CONTROL._ PROVIDING DEFAULT VALUE val age = failAsValue(classOf[NumberFormatException])(0) { input.toInt }
  • 54. SCALA.UTIL.CONTROL._ WHAT ABOUT FINALLY With catch logic No catch logic catching(classOf[NumberFormatException]).andFinally { println("Age parsed somehow") }.apply { input.toInt } ultimately(println("Age parsed somehow")) { input.toInt }
  • 55. SCALA.UTIL.CONTROL._ There's more to cover and explore, please check out the .Scala documentation
  • 56. THANKS FOR YOUR ATTENTION