SlideShare a Scribd company logo
1 of 92
1
2
Protocol-oriented programming in Swift
Rostyslav Kobyzskyi
Software Engineer
16th Nov, 2016
3
1. Classes and problems
2. Start with Protocol
3. Using Protocols
4. Examples
5. Questions
Agenda
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
Why Protocols?
Classes
• Encapsulation
• Access Control
• Abstraction
• Namespace
• Expressive Syntax
• Extensibility
Classes
• Encapsulation
• Access Control
• Abstraction
• Namespace
• Expressive Syntax
• Extensibility
1. Implicit Sharing
A
B
Data
1. Implicit Sharing
A
B
Data
1. Implicit Sharing
A
B
Data
1. Implicit Sharing
A
B
Data
1. Implicit Sharing
A
B
Ponies
1. Implicit Sharing
B
Ponies
1. Implicit Sharing
B
Ponies
$@#$%?
1. Implicit Sharing
• Defensive Copy
• Inefficiency
• Race Condition
• Locks
• More Inefficiency
• Deadlock
• Complexity
• Bugs!
Values don’t Share.
That’s a good thing
Classes? They overshare…
2. Inheritance
Subclass
Stored
Properties
Superclass
2. Inheritance
One superclass
Subclass
Stored
Properties
Superclass
Instance
2. Inheritance
One superclass
Single Inheritance
Subclass
Stored
Properties
Superclass
Instance
2. Inheritance
One superclass
Single Inheritance
Super class may have Stored Properties
Subclass
Stored
Properties
Superclass
Stored
Properties
Instance
2. Inheritance
One superclass
Single Inheritance
Super class may have Stored Properties
• You must accept them
Subclass
Stored
Properties
Superclass
Stored
Properties
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
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
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
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
}
3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool { }
}
3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
{ fatalError(“implement me!”) }
3. Lost Type Relationships
class Ordered {
func precedes(other: Ordered) -> Bool
}
{ fatalError(“implement me!”) } X
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
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
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
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`
`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
}
}
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
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
Swift is Protocol-Oriented
Programming Language
Start with a Protocol
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
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
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
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
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
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}
}
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
}
}
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
}
}
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
}
}
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
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
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
}
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
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
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
}
Two-world of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool func precedes(other: Self) -> Bool
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])
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
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
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
A Primitive “Render”
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Drawable
protocol Drawable {
func draw(randerer: Renderer)
}
Polygon
protocol Drawable {
func draw(randerer: Renderer)
}
struct Polygon: Drawable {
func draw(renderer: Renderer) {
renderer.moveTo(corners.last!)
for p in corners {
renderer.lineTo(p)
}
}
var corners: [CGPoint] = []
}
Circle
protocol Drawable {
func draw(randerer: Renderer)
}
struct Circle: Drawable {
func draw(renderer: Renderer) {
renderer.artAt(center, radius: radius,
startAngle: 0.0, endAngle: twoPi)
}
}
var center: CGPoint
var radius: CGFloat
}
Diagram
protocol Drawable {
func draw(randerer: Renderer)
}
struct Diagram: Drawable {
func draw(renderer: Renderer) {
for f in elements {
f.draw(renderer)
}
}
var elements: [Drawable] = []
}
Test It!
var circle = Circle(
center: CGPoint(x: 187.5, y: 333.5),
radius: 93.75
)
Test It!
var circle = Circle(
center: CGPoint(x: 187.5, y: 333.5),
radius: 93.75
)
var triangle = Polygon(corners: [
CGPoint(x: 187.5, y: 427.25),
CGPoint(x: 268.69, y: 286.625),
CGPoint(x: 106.31, y: 286.625)
])
Test It!
var circle = Circle(
center: CGPoint(x: 187.5, y: 333.5),
radius: 93.75
)
var triangle = Polygon(corners: [
CGPoint(x: 187.5, y: 427.25),
CGPoint(x: 268.69, y: 286.625),
CGPoint(x: 106.31, y: 286.625)
])
var diagram = Diagram(elements: [circle: triangle])
Test It!
var circle = Circle(
center: CGPoint(x: 187.5, y: 333.5),
radius: 93.75
)
var triangle = Polygon(corners: [
CGPoint(x: 187.5, y: 427.25),
CGPoint(x: 268.69, y: 286.625),
CGPoint(x: 106.31, y: 286.625)
])
var diagram = Diagram(elements: [circle: triangle])
diagram.draw(Renderer())
Renderer as Protocol
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Renderer as Protocol
protocol Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Renderer as Protocol
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Renderer as Protocol
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
struct Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Renderer as Protocol
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
struct TestRenderer: Renderer {
func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) }
func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
print(“arcAt((center), radius: (radius)),” +
+ “ startAngle: (startAngle), endAngle: (endAngle)”)
}
}
Rendering with CoreGraphics
Retroactive modeling
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
Rendering with CoreGraphics
Retroactive modeling
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
Rendering with CoreGraphics
Retroactive modeling
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat)
}
extension CGContext: Renderer {
func moveTo(p: CGPoint) { }
func lineTo(p: CGPoint) { }
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) { }
}
Rendering with CoreGraphics
Retroactive modeling
extension CGContext: Renderer {
func moveTo(p: CGPoint) {
CGContextMoveToPoint(self, p.x, p.y)
}
func lineTo(p: CGPoint) {
CGContextAddLineToPoint(self, p.x, p.y)
}
func arcAt(center: CGPoint, radius: CGFloat,
startAngler: CGFloat, endAngle: CGFloat) {
let arc = CGPathCreateMutable()
CGPathAddArc(arc, nil, center.x, center.y, radius,
startAngle, endAngle, true)
CGContextAddPath(self, arc)
}
}
Protocols and Generics for Testability
So much better than mocks
struct Bubble: Drawable {
func draw(r: Renderer) {
r.arcAt(center, radius, startAngle: 0, endAngle: twoPi)
r.arcAt(highlightCenter, radius: highlightRadius,
startAngle: 0, endAngle: twoPi
)
}
}
Protocols and Generics for Testability
So much better than mocks
struct Bubble: Drawable {
func draw(r: Renderer) {
r.arcAt(center, radius, startAngle: 0, endAngle: twoPi)
r.arcAt(highlightCenter, radius: highlightRadius,
startAngle: 0, endAngle: twoPi
)
}
}
struct Circle: Drawable {
func draw(r: Renderer) {
r.arcAt(center, radius, startAngle: 0, endAngle: twoPi)
}
}
Protocols and Generics for Testability
So much better than mocks
struct Bubble: Drawable {
func draw(r: Renderer) {
r.circleAt(center, radius)
r.arcAt(highlightCenter, radius: highlightRadius)
}
}
struct Circle: Drawable {
func draw(r: Renderer) {
r.circleAt(center, radius)
}
}
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
New requirement
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
extension TestRenderer {
func circleAt(center: CGPoint, radius: CGFloat) {
arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi)
}
}
Adding a Circle Primitive
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
extension CGContext {
func circleAt(center: CGPoint, radius: CGFloat) {
arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi)
}
}
Protocol Extension
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) {
arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi)
}
}
New!
Protocol Extension
protocol Renderer {
func moveTo(p: CGPoint)
func lineTo(p: CGPoint)
func circleAt(center: CGPoint, radius: CGFloat)
func arcAt(
center: CGPoint, radius: CGFloat,
startAngle: CGFloat, endAngle: CGFloat)
)
}
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) {
arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi)
}
}
Shared Implementation
Protocol Extension
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
extension TestRenderer: Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
Protocol Extension
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
extension TestRenderer: Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
let r = TestRenderer()
r.circleAt(origin, radius: 1)
r.rectangleAt(edges)
Protocol Extension
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
extension TestRenderer: Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
let r = TestRenderer()
r.circleAt(origin, radius: 1)
r.rectangleAt(edges)
Protocol Extension
customization point
extension Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
extension TestRenderer: Renderer {
func circleAt(center: CGPoint, radius: CGFloat) { ... }
func rectagleAt(edges: CGRect) { ... }
}
let r: Renderer = TestRenderer()
r.circleAt(origin, radius: 1)
r.rectangleAt(edges)
91
Questions
92
Thank you
Rostyslav
Software Engineer
rostyslav.kobyzskyi@globallogic.com
+38-093-254-3392

More Related Content

What's hot

High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scala
djspiewak
 
String and string manipulation x
String and string manipulation xString and string manipulation x
String and string manipulation x
Shahjahan Samoon
 
Ti1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: PolymorphismTi1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: Polymorphism
Eelco Visser
 
String handling(string class)
String handling(string class)String handling(string class)
String handling(string class)
Ravi Kant Sahu
 

What's hot (20)

Sparql
SparqlSparql
Sparql
 
High Wizardry in the Land of Scala
High Wizardry in the Land of ScalaHigh Wizardry in the Land of Scala
High Wizardry in the Land of Scala
 
Introduction to the basics of Python programming (part 3)
Introduction to the basics of Python programming (part 3)Introduction to the basics of Python programming (part 3)
Introduction to the basics of Python programming (part 3)
 
The Ring programming language version 1.7 book - Part 39 of 196
The Ring programming language version 1.7 book - Part 39 of 196The Ring programming language version 1.7 book - Part 39 of 196
The Ring programming language version 1.7 book - Part 39 of 196
 
01 Java Language And OOP Part I LAB
01 Java Language And OOP Part I LAB01 Java Language And OOP Part I LAB
01 Java Language And OOP Part I LAB
 
DevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a DatastoreDevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a Datastore
 
Introduction to Python for Plone developers
Introduction to Python for Plone developersIntroduction to Python for Plone developers
Introduction to Python for Plone developers
 
String and string manipulation x
String and string manipulation xString and string manipulation x
String and string manipulation x
 
Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)
 
06 Java Language And OOP Part VI
06 Java Language And OOP Part VI06 Java Language And OOP Part VI
06 Java Language And OOP Part VI
 
Ti1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: PolymorphismTi1220 Lecture 7: Polymorphism
Ti1220 Lecture 7: Polymorphism
 
Strings in java
Strings in javaStrings in java
Strings in java
 
STRINGS IN JAVA
STRINGS IN JAVASTRINGS IN JAVA
STRINGS IN JAVA
 
FUNDAMENTALS OF PYTHON LANGUAGE
 FUNDAMENTALS OF PYTHON LANGUAGE  FUNDAMENTALS OF PYTHON LANGUAGE
FUNDAMENTALS OF PYTHON LANGUAGE
 
Functional concepts in C#
Functional concepts in C#Functional concepts in C#
Functional concepts in C#
 
Pythonppt28 11-18
Pythonppt28 11-18Pythonppt28 11-18
Pythonppt28 11-18
 
The Ring programming language version 1.9 book - Part 39 of 210
The Ring programming language version 1.9 book - Part 39 of 210The Ring programming language version 1.9 book - Part 39 of 210
The Ring programming language version 1.9 book - Part 39 of 210
 
Why Haskell
Why HaskellWhy Haskell
Why Haskell
 
Java Polymorphism Part 2
Java Polymorphism Part 2Java Polymorphism Part 2
Java Polymorphism Part 2
 
String handling(string class)
String handling(string class)String handling(string class)
String handling(string class)
 

Viewers also liked

Testing in swift
Testing in swiftTesting in swift
Testing in swift
hugo lu
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
nickokiss
 
UNIT TESTING PPT
UNIT TESTING PPTUNIT TESTING PPT
UNIT TESTING PPT
suhasreddy1
 

Viewers also liked (14)

Unit Testing in Swift
Unit Testing in SwiftUnit Testing in Swift
Unit Testing in Swift
 
Bluetooth LE: User Experience with iOS
Bluetooth LE: User Experience with iOSBluetooth LE: User Experience with iOS
Bluetooth LE: User Experience with iOS
 
Annual report 2015 web
Annual report 2015 webAnnual report 2015 web
Annual report 2015 web
 
Swift testing ftw
Swift testing ftwSwift testing ftw
Swift testing ftw
 
Unit testing in swift 2 - The before & after story
Unit testing in swift 2 - The before & after storyUnit testing in swift 2 - The before & after story
Unit testing in swift 2 - The before & after story
 
Testing iOS10 Apps with Appium and its new XCUITest backend
Testing iOS10 Apps with Appium and its new XCUITest backendTesting iOS10 Apps with Appium and its new XCUITest backend
Testing iOS10 Apps with Appium and its new XCUITest backend
 
Testing in swift
Testing in swiftTesting in swift
Testing in swift
 
Generating test cases using UML Communication Diagram
Generating test cases using UML Communication Diagram Generating test cases using UML Communication Diagram
Generating test cases using UML Communication Diagram
 
7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOS7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOS
 
iOS Unit Testing Like a Boss
iOS Unit Testing Like a BossiOS Unit Testing Like a Boss
iOS Unit Testing Like a Boss
 
iOS advanced architecture workshop 3h edition
iOS advanced architecture workshop 3h editioniOS advanced architecture workshop 3h edition
iOS advanced architecture workshop 3h edition
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
 
Unit Testing Concepts and Best Practices
Unit Testing Concepts and Best PracticesUnit Testing Concepts and Best Practices
Unit Testing Concepts and Best Practices
 
UNIT TESTING PPT
UNIT TESTING PPTUNIT TESTING PPT
UNIT TESTING PPT
 

Similar to Protocol-Oriented Programming in Swift

Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
Yandex
 
TI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type ParameterizationTI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type Parameterization
Eelco Visser
 
Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9
sagaroceanic11
 
Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9
sagaroceanic11
 
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
Maulik Borsaniya
 

Similar to Protocol-Oriented Programming in Swift (20)

Class 2 - Introduction to PHP
Class 2 - Introduction to PHPClass 2 - Introduction to PHP
Class 2 - Introduction to PHP
 
Lambdas and Laughs
Lambdas and LaughsLambdas and Laughs
Lambdas and Laughs
 
SPARQL introduction and training (130+ slides with exercices)
SPARQL introduction and training (130+ slides with exercices)SPARQL introduction and training (130+ slides with exercices)
SPARQL introduction and training (130+ slides with exercices)
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
PythonStudyMaterialSTudyMaterial.pdf
PythonStudyMaterialSTudyMaterial.pdfPythonStudyMaterialSTudyMaterial.pdf
PythonStudyMaterialSTudyMaterial.pdf
 
Linq Introduction
Linq IntroductionLinq Introduction
Linq Introduction
 
Scala for curious
Scala for curiousScala for curious
Scala for curious
 
2. overview of c#
2. overview of c#2. overview of c#
2. overview of c#
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
Ruby Basics
Ruby BasicsRuby Basics
Ruby Basics
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Ruby basics
Ruby basicsRuby basics
Ruby basics
 
Of Lambdas and LINQ
Of Lambdas and LINQOf Lambdas and LINQ
Of Lambdas and LINQ
 
TI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type ParameterizationTI1220 Lecture 8: Traits & Type Parameterization
TI1220 Lecture 8: Traits & Type Parameterization
 
Refactoring bad codesmell
Refactoring bad codesmellRefactoring bad codesmell
Refactoring bad codesmell
 
Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9
 
Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9Rubyforjavaprogrammers 1210167973516759-9
Rubyforjavaprogrammers 1210167973516759-9
 
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...PYTHON -Chapter 2 - Functions,   Exception, Modules  and    Files -MAULIK BOR...
PYTHON -Chapter 2 - Functions, Exception, Modules and Files -MAULIK BOR...
 
TEMPLATES IN JAVA
TEMPLATES IN JAVATEMPLATES IN JAVA
TEMPLATES IN JAVA
 
Scala in practice - 3 years later
Scala in practice - 3 years laterScala in practice - 3 years later
Scala in practice - 3 years later
 

More from GlobalLogic Ukraine

GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Ukraine
 

More from GlobalLogic Ukraine (20)

GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
 
Штучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptxШтучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptx
 
Задачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptxЗадачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptx
 
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptxЩо треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
 
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
 
JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"
 
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
 
Страх і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic EducationСтрах і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic Education
 
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
 
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
 
“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?
 
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
 
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
 
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
 
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
 
GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"
 
C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"
 
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
 
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
 
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
 

Recently uploaded

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 

Recently uploaded (20)

Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 

Protocol-Oriented Programming in Swift

  • 1. 1
  • 2. 2 Protocol-oriented programming in Swift Rostyslav Kobyzskyi Software Engineer 16th Nov, 2016
  • 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
  • 6. Classes • Encapsulation • Access Control • Abstraction • Namespace • Expressive Syntax • Extensibility
  • 7. Classes • Encapsulation • Access Control • Abstraction • Namespace • Expressive Syntax • Extensibility
  • 15. 1. Implicit Sharing • Defensive Copy • Inefficiency • Race Condition • Locks • More Inefficiency • Deadlock • Complexity • Bugs!
  • 16. Values don’t Share. That’s a good thing Classes? They overshare…
  • 19. Instance 2. Inheritance One superclass Single Inheritance Subclass Stored Properties Superclass
  • 20. Instance 2. Inheritance One superclass Single Inheritance Super class may have Stored Properties Subclass Stored Properties Superclass Stored Properties
  • 21. Instance 2. Inheritance One superclass Single Inheritance Super class may have Stored Properties • You must accept them Subclass Stored Properties Superclass Stored Properties
  • 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
  • 37. Start with a Protocol
  • 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
  • 58. A Primitive “Render” struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 59. Drawable protocol Drawable { func draw(randerer: Renderer) }
  • 60. Polygon protocol Drawable { func draw(randerer: Renderer) } struct Polygon: Drawable { func draw(renderer: Renderer) { renderer.moveTo(corners.last!) for p in corners { renderer.lineTo(p) } } var corners: [CGPoint] = [] }
  • 61. Circle protocol Drawable { func draw(randerer: Renderer) } struct Circle: Drawable { func draw(renderer: Renderer) { renderer.artAt(center, radius: radius, startAngle: 0.0, endAngle: twoPi) } } var center: CGPoint var radius: CGFloat }
  • 62. Diagram protocol Drawable { func draw(randerer: Renderer) } struct Diagram: Drawable { func draw(renderer: Renderer) { for f in elements { f.draw(renderer) } } var elements: [Drawable] = [] }
  • 63. Test It! var circle = Circle( center: CGPoint(x: 187.5, y: 333.5), radius: 93.75 )
  • 64. Test It! var circle = Circle( center: CGPoint(x: 187.5, y: 333.5), radius: 93.75 ) var triangle = Polygon(corners: [ CGPoint(x: 187.5, y: 427.25), CGPoint(x: 268.69, y: 286.625), CGPoint(x: 106.31, y: 286.625) ])
  • 65. Test It! var circle = Circle( center: CGPoint(x: 187.5, y: 333.5), radius: 93.75 ) var triangle = Polygon(corners: [ CGPoint(x: 187.5, y: 427.25), CGPoint(x: 268.69, y: 286.625), CGPoint(x: 106.31, y: 286.625) ]) var diagram = Diagram(elements: [circle: triangle])
  • 66. Test It! var circle = Circle( center: CGPoint(x: 187.5, y: 333.5), radius: 93.75 ) var triangle = Polygon(corners: [ CGPoint(x: 187.5, y: 427.25), CGPoint(x: 268.69, y: 286.625), CGPoint(x: 106.31, y: 286.625) ]) var diagram = Diagram(elements: [circle: triangle]) diagram.draw(Renderer())
  • 67. Renderer as Protocol struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } } struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 68. Renderer as Protocol protocol Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } } struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 69. Renderer as Protocol protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) } struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 70. Renderer as Protocol protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) } struct Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 71. Renderer as Protocol protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) } struct TestRenderer: Renderer { func moveTo(p: CGPoint) { print(“moveTo((p.x), (p.y))”) } func lineTo(p: CGPoint) { print(“lineTo((p.x), (p.y))”) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { print(“arcAt((center), radius: (radius)),” + + “ startAngle: (startAngle), endAngle: (endAngle)”) } }
  • 72. Rendering with CoreGraphics Retroactive modeling protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) }
  • 73. Rendering with CoreGraphics Retroactive modeling protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) }
  • 74. Rendering with CoreGraphics Retroactive modeling protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) } extension CGContext: Renderer { func moveTo(p: CGPoint) { } func lineTo(p: CGPoint) { } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { } }
  • 75. Rendering with CoreGraphics Retroactive modeling extension CGContext: Renderer { func moveTo(p: CGPoint) { CGContextMoveToPoint(self, p.x, p.y) } func lineTo(p: CGPoint) { CGContextAddLineToPoint(self, p.x, p.y) } func arcAt(center: CGPoint, radius: CGFloat, startAngler: CGFloat, endAngle: CGFloat) { let arc = CGPathCreateMutable() CGPathAddArc(arc, nil, center.x, center.y, radius, startAngle, endAngle, true) CGContextAddPath(self, arc) } }
  • 76. Protocols and Generics for Testability So much better than mocks struct Bubble: Drawable { func draw(r: Renderer) { r.arcAt(center, radius, startAngle: 0, endAngle: twoPi) r.arcAt(highlightCenter, radius: highlightRadius, startAngle: 0, endAngle: twoPi ) } }
  • 77. Protocols and Generics for Testability So much better than mocks struct Bubble: Drawable { func draw(r: Renderer) { r.arcAt(center, radius, startAngle: 0, endAngle: twoPi) r.arcAt(highlightCenter, radius: highlightRadius, startAngle: 0, endAngle: twoPi ) } } struct Circle: Drawable { func draw(r: Renderer) { r.arcAt(center, radius, startAngle: 0, endAngle: twoPi) } }
  • 78. Protocols and Generics for Testability So much better than mocks struct Bubble: Drawable { func draw(r: Renderer) { r.circleAt(center, radius) r.arcAt(highlightCenter, radius: highlightRadius) } } struct Circle: Drawable { func draw(r: Renderer) { r.circleAt(center, radius) } }
  • 79. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) }
  • 80. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) }
  • 81. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) }
  • 82. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) } New requirement
  • 83. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) } extension TestRenderer { func circleAt(center: CGPoint, radius: CGFloat) { arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi) } }
  • 84. Adding a Circle Primitive protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) } extension CGContext { func circleAt(center: CGPoint, radius: CGFloat) { arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi) } }
  • 85. Protocol Extension protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) } extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi) } } New!
  • 86. Protocol Extension protocol Renderer { func moveTo(p: CGPoint) func lineTo(p: CGPoint) func circleAt(center: CGPoint, radius: CGFloat) func arcAt( center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat) ) } extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { arcAt(center, radius: radius, startAngle: 0, endAngle: twoPi) } } Shared Implementation
  • 87. Protocol Extension extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } extension TestRenderer: Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } }
  • 88. Protocol Extension extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } extension TestRenderer: Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } let r = TestRenderer() r.circleAt(origin, radius: 1) r.rectangleAt(edges)
  • 89. Protocol Extension extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } extension TestRenderer: Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } let r = TestRenderer() r.circleAt(origin, radius: 1) r.rectangleAt(edges)
  • 90. Protocol Extension customization point extension Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } extension TestRenderer: Renderer { func circleAt(center: CGPoint, radius: CGFloat) { ... } func rectagleAt(edges: CGRect) { ... } } let r: Renderer = TestRenderer() r.circleAt(origin, radius: 1) r.rectangleAt(edges)