Skip to content

Instantly share code, notes, and snippets.

@loufranco
Last active August 29, 2015 14:13
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 loufranco/f3edb6fb9acc4883aea8 to your computer and use it in GitHub Desktop.
Save loufranco/f3edb6fb9acc4883aea8 to your computer and use it in GitHub Desktop.
Wrapping Swift Pattern Matching in a Closure
import Foundation
import Darwin
// Given Box and Result definitions from "Functional Programming in Swift"
// Buy it here: http://objc.io/books
// You need Box because Swift can't handle generics in Enums directly
public class Box<T> {
let unbox:T
init(_ value:T) { self.unbox = value }
}
public enum Result<T> {
case Success(Box<T>) // case Success(T) does not compile
case Error(String, NSError?)
}
// I can declare a function that returns a result or an error
// This is better than an Optional, because I get the error message and info
func funcWithResult() -> Result<Int> {
// definition elided
return Result.Error("Not implemented", nil)
}
// I _could_ do something like this:
var result:Int
switch funcWithResult() {
case let Result.Success(box):
result = box.unbox
case let Result.Error(msg, error):
// deal with error case, but what do you do about result?
println("Error: \(msg)")
}
// which is fine when you don't need to define anything for later
// But, we can't be sure result is defined, and we can't use let (for immutability)
// We could use Int?, but really, if we don't have a result we just want to bail here and go forward with Int
// So, do this instead
let immutableResult:Int = { switch funcWithResult() {
case let Result.Success(box):
return box.unbox
case let Result.Error(msg, error):
// deal with error case
// in my case, I am scripting, so I call an @noreturn function and bail the script
// Swift knows that this branch never returns and can analyze code paths correctly
exit(-1)
}
}()
// If your error case can't return something sensible, then
let immutableOptionalResult:Int? = { switch funcWithResult() {
case let Result.Success(box):
return box.unbox
case let Result.Error(msg, error):
// deal with error case
return nil
}
}()
// or ...
if let immutableOptionalResultChecked:Int = { switch funcWithResult() {
case let Result.Success(box):
return box.unbox
case let Result.Error(msg, error):
// deal with error case
return nil
}
}() {
// immutableOptionalResultChecked can safely be used here
} else {
// you already handled the error, so bail or leave this out or whatever
}
// There's a trade-off here where you have to think about whether to continue with Result, an Int? or deal with
// the error and bail. In my case, I am at the top level of a script, I just want to exit() and go forward
// with immutable, simple, non-optional types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment