Skip to content

Instantly share code, notes, and snippets.

@heiko-henrich
Last active August 29, 2015 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heiko-henrich/953c80ec1f9b96008539 to your computer and use it in GitHub Desktop.
Save heiko-henrich/953c80ec1f9b96008539 to your computer and use it in GitHub Desktop.
Result Error Handling and Monad Error Handling (Result Type) working together
/// simple Error Type
struct Error: ErrorType {}
/// the error handling monad
enum Result<T> {
case Value(T)
case Error(ErrorType)
}
/// this operator transforms a throwing function result in a resutl type
/// I would have preferred a prefix operator, but this forces to use parens which is awkward
postfix operator +/-? {}
postfix func +/-?<T>(@autoclosure f: () throws -> T ) -> Result<T> {
do {
return Result.Value(try f())
}
catch let e {
return Result.Error(e)
}
}
/// example
func throwWhenOdd(i: Int) throws -> Int {
if i % 2 != 0 {
throw Error()
}
else {
return i
}
}
let result1 = try throwWhenOdd(5)+/-?
let result2 = try throwWhenOdd(6)+/-?
/// extension to Result "unwraps" Result and throws, when an error is found
extension Result {
func throwing() throws -> T {
switch self {
case let .Value(value): return value
case let .Error(error): throw error
}
}
}
/// example
try? result1.throwing()
try? result2.throwing()
/// this operator turns an Optional into a Result
infix operator +/-?? {
associativity right
precedence 131
}
func +/-??<T>(opt: T?, error:ErrorType) -> Result<T> {
return opt == nil ? Result.Error(error) : Result.Value(opt!)
}
/// example
let opt1: Int? = nil
let opt2: Int? = 5
opt1 +/-?? Error()
opt2 +/-?? Error()
/// this is the opposite of the try? keyword,
/// which unwraps an optional and throws an error when failing
infix operator !! {
associativity right
precedence 131
}
func !!<T>(opt: T?, error:ErrorType) throws -> T{
if let opt = opt {
return opt
}
else {
throw error
}
}
/// example
do {
print("success", try opt2 !! Error())
// will throw here:
print("more success", try opt1 !! Error())
}
catch let e {
print("error!!!", e)
}
// success 5
// error!!! Error()
@heiko-henrich
Copy link
Author

There is a lot of discussion about the new swift error handling and how error handling ought to be.
A lot of frameworks (like reactiive cocoa, RXSwift among others) use an algebraic Result type to promote errors. swift tries a new way somewhrere between the old fashoned try catch construct and functions which might return errors.
I don't think these are mutually exclusive paths.
Since XCode 7b6 @autoclosure can throw errors, so it's easy to convert a throwing function in an expression which yields a "Result"
On the other hand, the try? keyword transforms a throwing function result in an Optional.
It' easy to do the opposite:
the !! operator here kind of force unwraps the optional and throws an error when failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment