Skip to content

Instantly share code, notes, and snippets.

@hartbit
Created November 11, 2014 16:37
Show Gist options
  • Save hartbit/6687edc9e0cd38170bc4 to your computer and use it in GitHub Desktop.
Save hartbit/6687edc9e0cd38170bc4 to your computer and use it in GitHub Desktop.
// Trying to write a function that does some select/map magic with easy error handling
let cities = [[
"name": "Geneva",
"population": 184538
],[
"name": "Bern",
"population": 123154
], [
"name": "Zurich",
"population": 366765
], [
"name": "Rubish",
"population": -500
]]
struct City {
let name: String
let population: Int
init?(name: String, population: Int) {
if population > 0 {
self.name = name
self.population = population
} else {
return nil
}
}
}
// 1. No error handling
// -> Easy but crash prone
func citiesFromJSON(json: [[String:Any]]) -> [City] {
return json.map({ (dictionary: [String:Any]) -> City in
return City(name: dictionary["name"] as String, population: dictionary["population"] as Int)!
})
}
// 2. for loop NSError solution
// -> Crash resistent but not very functional
func citiesFromJSON(json: [[String:Any]], error: NSErrorPointer) -> [City] {
var cities: [City] = []
for dictionary in json {
if let name = dictionary["name"] as? String {
if let population = dictionary["population"] as? Int {
if let city = City(name: name, population: population) {
cities.append(city)
continue
}
}
}
error.memory = NSError(domain: "domain", code: 666, userInfo: nil)
return []
}
return cities
}
// 2. Functional Result<T> solution
// -> Crash resistent but loops through everything before detecting errors and difficult to write
enum Result<T> {
case Success(@autoclosure () -> T)
case Failure(NSError)
}
func citiesFromJSON(json: [[String:Any]]) -> Result<[City]> {
return json.map({ dictionary -> Result<City> in
if let name = dictionary["name"] as? String {
if let population = dictionary["population"] as? Int {
if let city = City(name: name, population: population) {
return .Success(city)
}
}
}
return .Failure(NSError(domain: "domain", code: 666, userInfo: nil))
}).reduce(Result.Success([]), combine: { (result, cityResult) -> Result<[City]> in
switch (result, cityResult) {
case (.Failure, _):
return result
case (_, .Failure(let error)):
return .Failure(error)
case (.Success(let cities), .Success(let city)):
return .Success(cities() + [city()])
default:
assertionFailure("should never happen")
}
})
}
// 3. PromiseKit maps??
// -> Perfect!
func citiesFromJSON(json: [[String:Any]]) -> Result<[City]> {
return json.map({ dictionary in
if let name = dictionary["name"] as? String {
if let population = dictionary["population"] as? Int {
if let city = City(name: name, population: population) {
return city
}
}
}
return NSError(domain: "domain", code: 666, userInfo: nil)
}).catch { error in
return .Failure(error)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment