Skip to content

Instantly share code, notes, and snippets.

@nkpart
Last active January 18, 2017 00:15
Show Gist options
  • Save nkpart/1c4b70eeb33c3a1a66adcf7927311e6a to your computer and use it in GitHub Desktop.
Save nkpart/1c4b70eeb33c3a1a66adcf7927311e6a to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import Cocoa
import Foundation
// 0. BASE CASE
// Our Error enum
enum FailsUserI {
case duplicateI
}
// Our logic
func checkUserB(_ u : String) -> FailsUserI? {
if u == "nick" {
return .duplicateI
} else {
return nil
}
}
let _ : FailsUserI? = checkUserB("nick")
// 1. Abstract the Construction of the Error
// We define the FailsUserI case constructors as static functions on a protocol
protocol FailsUser {
static func duplicate() -> Self
}
// The change to our function is to call the protocol functions to construct errors
func checkUser<E: FailsUser>(_ u : String) -> E? {
if u == "nick" {
return E.duplicate()
} else {
return nil
}
}
// To recover the original behaviour, we implement the protocol:
extension FailsUserI : FailsUser {
static func duplicate() -> FailsUserI {
return .duplicateI
}
}
let x: FailsUserI? = checkUser("nick")
// 2. Use our function with a different error type
// A product of errors, could be more cases here, one of the cases is our user error
enum AppFails {
case userFails(FailsUserI)
}
// The construction here defers to the underlying FailsUserI interface
extension AppFails : FailsUser {
static func duplicate() -> AppFails {
return .userFails(FailsUserI.duplicate())
}
}
// Note that the code here is the same for the 'FailsUserI' case.
let y: AppFails? = checkUser("nick")
// 3. Compose Multiple Components together
// A second class of errors
protocol ApiErr {
static func serverDown() -> Self
}
// A second piece of app logic
func store<E: ApiErr> (_ u: String) -> E? {
if u == "ryan" {
return E.serverDown()
} else {
return nil
}
}
// A function that calls `store` and `checkUser`, note that the error protocols are unioned
func both<E: ApiErr & FailsUser>() -> E? {
let f: E? = store("ryan")
return f.flatMap { _ in checkUser("nick") }
}
// A concrete union of our 2 classes of errors
enum AppFails2 {
case duplicateUser
case noServer
}
extension AppFails2 : FailsUser {
static func duplicate() -> AppFails2 {
return .duplicateUser
}
}
extension AppFails2 : ApiErr {
static func serverDown() -> AppFails2 {
return .noServer
}
}
// The final call that does it all and produces the union
let z: AppFails2? = both()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment