Upload
rob-napier
View
11.999
Download
2
Embed Size (px)
Citation preview
// An Animal can eat protocol Animal { typealias Food func eat(food: Food) }
struct Cow: Animal { func eat(food: Grass) { print("moo") } }
struct Sheep: Animal { func eat(food: Grass) { print("bah") } }
let grassEaters: [Animal] = [Cow(), Sheep()]
error: protocol 'Animal' can only be used as a generic constraint because it has Self or associated type requirements
struct AnyAnimal<Food>: Animal {
init<A: Animal where A.Food == Food>(_ animal: A) { _eat = animal.eat }
func eat(food: Food) { _eat(food) }
private let _eat: (Food) -> Void }
let grassEaters = [AnyAnimal(Cow()), AnyAnimal(Sheep())]
for eater in grassEaters { eater.eat(Grass()) }
protocol Animal { typealias Food func eat(food: Food) }
struct AnyAnimal<Food>: Animal { func eat(food: Food) { _eat(food) }
init ...
private let _eat: (Food) -> Void }
struct Animal<Food> { let eat: (Food) -> Void }
protocol Animal { typealias Food func eat(food: Food) }
let grassEaters = [ Animal(eat: cow.eat), // method Animal(eat: { _ in print("bah") } ) // function literal ]
let session = NSURLSession() session.delegate = self let task = session.dataTaskWithURL(url)
let task = session.dataTaskWithURL(url, completionHandler: { ... })
DELEGATES
HANDLERS
SOME RULES OF THUMB
‣ One method? Maybe function.
‣ Three or more methods? Protocol.
‣ Relationship short-lived? Function.
‣ Relationship ongoing? Probably protocol/delegate.
protocol P { typealias A typealias B
func x(a: A) -> B func y(a: A) -> B}
struct S<A,B> { func x(a: A) -> B {…} func y(a: A) -> B {…}}
func x<A,B>(a: A) -> B {…}
func y<A,B>(a: A) -> B {…}
Pick the form that works best for your problem.
protocol Parsing { typealias Problem func parse(data: NSData) -> Problem }
protocol Searching { typealias Problem typealias Solution func search(problem: Problem) -> Solution }
protocol Outputting { typealias Solution func output(solution: Solution) }
struct Solver< Parser: Parsing, Searcher: Searching, Outputter: Outputting where Parser.Problem == Searcher.Problem, Searcher.Solution == Outputter.Solution >{ let parser: Parser let searcher: Searcher let outputter: Outputter
func solve(data: NSData) { outputter.output(searcher.search(parser.parse(data))) } }
protocol Solving { typealias Parser: Parsing typealias Searcher: Searching typealias Outputter: Outputting
var parser: Parser { get } var searcher: Searcher { get } var outputter: Outputter { get } }
extension Solving where Parser.Problem == Searcher.Problem, Searcher.Solution == Outputter.Solution { func solve(data: NSData) { outputter.output(searcher.search(parser.parse(data))) } }
struct SimpleSolver< Parser: Parsing, Searcher: Searching, Outputter: Outputting where Parser.Problem == Searcher.Problem, Searcher.Solution == Outputter.Solution >: Solving { let parser: Parser let searcher: Searcher let outputter: Outputter // ... }
All the code repetition was making him ornery, and if Crusty ain't happy, ain't nobody happy.
Protocol-Oriented Programming in Swift
protocol Solving { typealias Problem typealias Solution
func parse(data: NSData) -> Problem func search(problem: Problem) -> Solution func output(solution: Solution) -> Void }
extension Solving { func solve(data: NSData) { output(search(parse(data))) } }
struct SimpleSolver<Problem, Solution>: Solving { let _parse: (NSData) -> Problem let _search: (Problem) -> Solution let _output: (Solution) -> Void
init( parse: (NSData) -> Problem, search: (Problem) -> Solution, output: (Solution) -> Void) { _parse = parse _search = search _output = output }
func parse(data: NSData) -> Problem { return _parse(data) } func search(problem: Problem) -> Solution { return _search(problem) } func output(solution: Solution) { _output(solution) } //... }
protocol Solving { typealias Problem typealias Solution
var parse: (NSData) -> Problem { get } var search: (Problem) -> Solution { get } var output: (Solution) -> Void { get } }
extension Solving { func solve(data: NSData) { output(search(parse(data))) } }
struct SimpleSolver<Problem, Solution>: Solving { let parse: (NSData) -> Problem let search: (Problem) -> Solution let output: (Solution) -> Void // ... }
SimpleSolver
ParserSearcherOutputter
“Simple” functions
FancySolver
ParserSearcherOutputter
“Fancy” functions“Simple” properties “Fancy” properties
SolvingParserSearcherOutputter
SimpleSolver
“Simple” functions
FancySolver
“Fancy” functions“Simple” properties “Fancy” properties
SolverConfigParserSearcherOutputter
Config Config
struct SolverConfig<Problem, Solution> { let parse: (NSData) -> Problem let search: (Problem) -> Solution let output: (Solution) -> Void
func solve(data: NSData) { output(search(parse(data))) } }
struct SimpleSolver<Problem, Solution> { let config: SolverConfig<Problem, Solution> // ... }
protocol Parsing { typealias Problem func parse(data: NSData) -> Problem }
protocol Searching { typealias Problem typealias Solution func search(problem: Problem) -> Solution }
protocol Outputting { typealias Solution func output(solution: Solution) }
protocol Solving { typealias Parser: Parsing typealias Searcher: Searching typealias Outputter: Outputting
var parser: Parser { get } var searcher: Searcher { get } var outputter: Outputter { get } }
extension Solving where Parser.Problem == Searcher.Problem, Searcher.Solution == Outputter.Solution { func solve(data: NSData) { outputter.output(searcher.search(parser.parse(data))) } }
struct SimpleSolver< Parser: Parsing, Searcher: Searching, Outputter: Outputting where Parser.Problem == Searcher.Problem, Searcher.Solution == Outputter.Solution >: Solving { let parser: Parser let searcher: Searcher let outputter: Outputter // ... }
struct SolverConfig<Problem, Solution> { let parse: (NSData) -> Problem let search: (Problem) -> Solution let output: (Solution) -> Void
func solve(data: NSData) { output(search(parse(data))) } }
struct SimpleSolver<Problem, Solution> { let config: SolverConfig<Problem, Solution> // ... }