Skip to content

Protocol Oriented Programming

Ben Guo edited this page Jun 18, 2015 · 7 revisions

(WWDC15-408)

Both types and classes provide:

  • Encapsulation
  • Access Control
  • Abstraction
  • Namespace
  • Expressive Syntax
  • Customization points and reuse

Classes are bad:

  • Implicit sharing
  • Class inheritance is too intrusive
    • single inheritance weight gain
    • no retroactive modeling (need superclass first)
    • superclass may have stored properties (initialization burden)
    • don't break superclass invariants!
    • know what/how to override (and when not to)
  • Lost type relationships

"Swift is a protocol-oriented programming language"

"Start with a protocol"

Self requirements

  • Protocol with self requirement means homogeneous, static dispatch

Testing

  • Protocols and generics are better than mocks for testing
    • mocks are inherently fragile and don't play well with static type system

Protocol Extensions

protocol Renderer {
    func moveTo(p: _)
    func circleAt(center: _, radius: _) { ... }
}

extension Renderer {
    func circleAt(center: _, radius: _) { ... }
    func rectangleAt(edges: _) { ... }
}

extension TestRenderer : Renderer {
    func circleAt(center: _, radius: _) { ... }
    func rectangleAt(edges: _) { ... }
}

let r: Renderer = TestRenderer()
r.circleAt(origin, radius: 1)   
// TestRenderer->circleAt 
// Because circleAt is a requirement, our model has the privilege of customizing it
r.rectangleAt(edges)            
// Renderer->rectangleAt
// rectangelAt isn't a requirement. TestRenderer's implementation shadows the protocol implementation, so protocol implementation is called.

More protocol extension tricks

  • Constrained extensions
    • extension CollectionType where Generator.Element : Equatable {
    • extension Ordered where Self : Comparable
  • Nicer looking generics
extension CollectionType where Index == RandomAccessIndexType,
Generator.Element : Ordered {
    func binarySearch(forKey: Generator.Element) -> Int {

    }
}

When to use classes

You want implicit sharing when

  • copying or comparing instances doesn't make sense (e.g. Window)
  • Instance lifetime is tied to external effects (e.g. TemporaryFile)
  • Instances are just "sinks"– write-only conduits to external state (e.g. CGContext)

Don't fight the system

  • When factoring something out a class, consider a value type
Clone this wiki locally