Created
November 11, 2014 16:37
-
-
Save hartbit/6687edc9e0cd38170bc4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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