These slides demonstrate how to use protocol-oriented programming in Swift. They contain vast information on classes, implicit sharing, inheritance, lost type relationships, useful pieces of advice and examples of using protocols.
This presentation by Rostyslav Kobyzskyi, GlobalLogic expert, was delivered at GlobalLogic Lviv iOS TechTalk on November 16, 2016.
Learn more: https://www.globallogic.com/ua/gl_news/globallogic-lviv-ios-techtalk-summary
3. 3
1. Classes and problems
2. Start with Protocol
3. Using Protocols
4. Examples
5. Questions
Agenda
4. Dave Abrahams
• David Abrahams is a computer
programmer and author
• Abrahams became a member of
the C++ Standards Committee
in 1996
• In 2013 Abrahams became an
employee at Apple Inc, where
he is involved in the
development of the Swift
programming language
22. 2. Inheritance
One superclass
Single Inheritance
Super class may have Stored Properties
• You must accept them
• Initialization problem
Instance
Subclass
Stored
Properties
Superclass
Stored
Properties
23. 2. Inheritance
One superclass
Single Inheritance
Super class may have Stored Properties
• You must accept them
• Initialization problem
• Don’t break superclass invariants!
Instance
Subclass
Stored
Properties
Superclass
Stored
Properties
24. 2. Inheritance
One superclass
Single Inheritance
Super class may have Stored Properties
• You must accept them
• Initialization problem
• Don’t break superclass invariants!
Know what/how to override (and when not)
Instance
Subclass
Stored
Properties
Superclass
Stored
Properties
25. 3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
func binarySearch(sortedKeys: [Ordered], forKey k: Ordered) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].precedes(k) { lo = mid + 1 }
else { hi = mid }
}
return lo
}
26. 3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool { }
}
27. 3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
{ fatalError(“implement me!”) }
28. 3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
{ fatalError(“implement me!”) } X
29. 3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
{ fatalError(“implement me!”) } X
30. class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
3. Lost Type Relationships
{ fatalError(“implement me!”) } X
31. class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
3. Lost Type Relationships
{ fatalError(“implement me!”) } X
32. class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
3. Lost Type Relationships
{ fatalError(“implement me!”) } X
`Ordered` does not have a member named `value`
33. `Ordered` does not have a member named `value`
3. Lost Type Relationships
{ fatalError(“implement me!”) } X
class Ordered {
func precedes(other: Ordered) -> Bool
}
class Label: Ordered { var text: String = “” ... }
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
34. class Ordered {
func precedes(other: Ordered) -> Bool
}
class Label: Ordered { var text: String = “” ... }
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
3. Lost Type Relationships
{ fatalError(“implement me!”) } X
35. A better Abstraction
Mechanism
• Support value types (and classes)
• Support static type relationships (and dynamic dispatch)
• Non-monolithic
• Doesn’t impose instance data on models
• Doesn’t impose initialization burdens on models
• Makes clear what to implement
38. Starting override with Protocols
class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < other.value
}
}
{ fatalError(“implement me!”) } X
39. Starting override with Protocols
class Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
{ fatalError(“implement me!”) } X
40. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
{ fatalError(“implement me!”) } X
41. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
{ fatalError(“implement me!”) }
Protocol methods may not have bodies
42. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
Method does not override any method
from superclass
43. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
class Number: Ordered {
var value: Double = 0
override fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value}
}
44. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
struct Number: Ordered {
var value: Double = 0
fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
45. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
struct Number: Ordered {
var value: Double = 0
fund precedes(other: Ordered) -> Bool {
return value < (other as! Number).value
}
}
46. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
struct Number: Ordered {
var value: Double = 0
fund precedes(other: Number) -> Bool {
return value < other.value
}
}
47. Starting override with Protocols
protocol Ordered {
func precedes(other: Ordered) -> Bool
}
struct Number: Ordered {
var value: Double = 0
fund precedes(other: Number) -> Bool {
return value < other.value
}
}
Protocol requires function ‘precedes’ with type ‘(Oredered)’ -> Bool
candidate has non-matching type (`Number`) -> Bool
48. Starting override with Protocols
protocol Ordered {
func precedes(other: Self) -> Bool
}
struct Number: Ordered {
var value: Double = 0
fund precedes(other: Number) -> Bool {
return value < other.value
}
}
Self requirement
49. Using out Protocol
func binarySearch(sortedKeys: [Ordered], forKey k: Ordered) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].precedes(k) { lo = mid + 1 }
else { hi = mid }
}
return lo
}
50. Using out Protocol
func binarySearch(sortedKeys: [Ordered], forKey k: Ordered) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].precedes(k) { lo = mid + 1 }
else { hi = mid }
}
return lo
}
Protocol ‘Ordered’ can only be used as a generic constraint
because if has Self or associated type requirements
51. Using out Protocol
func binarySearch(sortedKeys: [Ordered], forKey k: Ordered) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].precedes(k) { lo = mid + 1 }
else { hi = mid }
}
return lo
}
Protocol ‘Ordered’ can only be used as a generic constraint
because if has Self or associated type requirements
52. Using out Protocol
func binarySearch<T: Ordered>(sortedKeys: [T], forKey k: T) -> Int {
var lo = 0, hi = sortedKeys.count
while hi > lo {
let mid = lo + (hi - lo) / 2
if sortedKeys[mid].precedes(k) { lo = mid + 1 }
else { hi = mid }
}
return lo
}
53. Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool func precedes(other: Self) -> Bool
54. Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool
Usable as a type
sort(inout a: [Ordered])
func precedes(other: Self) -> Bool
Only usable as a generic constraint
sort<T: Ordered>(inout a: [T])
55. Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool
Usable as a type
sort(inout a: [Ordered])
Every model must deal with all others
func precedes(other: Self) -> Bool
Only usable as a generic constraint
sort<T: Ordered>(inout a: [T])
Models are free from interaction
56. Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool
Usable as a type
sort(inout a: [Ordered])
Every model must deal with all others
Dynamic dispatch
func precedes(other: Self) -> Bool
Only usable as a generic constraint
sort<T: Ordered>(inout a: [T])
Models are free from interaction
Static dispatch
57. Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool
Usable as a type
sort(inout a: [Ordered])
Every model must deal with all others
Dynamic dispatch
Less optimizable
func precedes(other: Self) -> Bool
Only usable as a generic constraint
sort<T: Ordered>(inout a: [T])
Models are free from interaction
Static dispatch
More optimizable