1. Fetch data from Github
extension URLSession {
func dataTask(
with url: URL,
completionHandler:
@escaping (Data?, URLResponse?, Error?) -> Void
) -> URLSessionDataTask
}
Slide 21
Slide 21 text
1. Fetch data from Github
completionHandler
=> Future
(Data?, URLResponse?, Error?)
=> Result
Future>
Slide 22
Slide 22 text
2. Deserialize
Result is a JSON object in form of an array of repos:
[
{
“name”: “repo_name”,
...
},
...
We want to know which ones of the repos couldn’t be deserialized
deserialize: (Data) throws -> [Data]
throws -> [Repo]
1. Create protocol
protocol ValidatedType {
associatedtype PA
associatedtype PE
}
extension Validated: ValidatedType {
typealias PA = A
typealias PE = E
}
Slide 45
Slide 45 text
2. Duplicate API in protocol (return concrete type)
protocol ValidatedType {
associatedtype PA
associatedtype PE
func map(_ f: (PA) -> B) -> Validated
}
extension Validated: ValidatedType {}
Slide 46
Slide 46 text
3. Implement the nested method in a constrained extension
extension Future where A: ValidatedType {
func map(
_ f: @escaping (A.PA) -> B
) -> Future> {
return map { $0.map(f) }
}
}
Slide 47
Slide 47 text
Method-based
1. Generalize the method,
not extension
2. Add constraints to
the method, not extension
Slide 48
Slide 48 text
1. Generalize the method, not extension
extension Future {
func map(
_ f: @escaping (VA) -> B
) -> Future> {
// work in progress
}
}
Slide 49
Slide 49 text
2. Add constraints to the method, not extension
extension Future {
func map(
_ f: @escaping (VA) -> B
) -> Future>
where A == Validated {
return map { $0.map(f) }
}
}
Slide 50
Slide 50 text
Now we can filter Swift repos!
let repos: Future<
Validated<
Array,
Either
>> = githubClient.fetch(.repos, for: user)
.map { deserialize($0) }
.map { // transforms described before }
repos.filter { (repo: Repo) -> Bool in
repo.language == “Swift”
} // it works!
Slide 51
Slide 51 text
A lot of
boilerplate?
Slide 52
Slide 52 text
Use code generation
(like Sourcery)
Please see this great talk for details:
Elviro Rocca — Protocol-Oriented Monad Transformers
https://www.youtube.com/watch?v=Zmb86zblcto
Slide 53
Slide 53 text
Use “wide”
container, like
Observable
Slide 54
Slide 54 text
Future< <== observable is async
Validated< <== observable can return error
Array< <== observable is sequence
Repo
>,
Either
>
>