Instantly share code, notes, and snippets.

Embed
What would you like to do?
Three Models of Failure Handling
// exception-passing style:
// wherein we pass an Exception back to the caller
// instead of the thing we promised them (surprise!).
class SomeFailure() extends Exception
def handleSomeFailure(err: SomeFailure): C = {
`appropriate C for this error`
}
def subroutine(a: A): B = {
if (`bad stuff`) throw SomeFailure
val b = `dat B`
b
}
def pipeline(): C = try {
val a = `get an A`
val b = subroutine(a)
val c = `process a B into a C`
c
} catch {
case err: SomeFailure => handleSomeFailure(err)
}
// continuation-passing style:
// wherein the caller supplies a continuation at the call site.
def subroutine(a: A)(cont: B => C): C = {
if (`bad stuff`) `appropriate C for this error` else {
val b = `dat B`
cont(b) }
}
def pipeline(a: A): C = {
val a = `get an A`
subroutine(a) { b =>
val c = `process a B into a C`
c }
}
// either-passing style:
// wherein we pass an `Either` to the caller.
def subroutine(a: A): Either[C, B] = {
if (`bad stuff`) Left(`appropriate C for this error`) else {
val b = `dat B`
Right(b) }
}
def pipeline(a: A): C = ( for {
a <- Right(`get an A`)
b <- subroutine(a)
c <- Right(`process a B into a C`)
} yield c ).fold(c => c)(c => c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment