Protocol Composition in Swift
What is protocol composition?
It is the process of combining multiple protocol into a single protocol. You can think of it as multiple inheritance except with protocols.
Let’s look at some examples.
The below implementation represents a dog which can bark and wag it’s tail when calling ballFound().
protocol CanDoDogThings {
func bark()
func waggTail()
}struct Runner {
let dog: CanDoDogThings
func ballFound() {
dog.waggTail()
dog.bark()
}
}
This is a simple and convenient implementation as it clearly defines what the dog is capable of doing when ball is found, wag it’s tail and bark. This approach can also be tested easily as the instances can be mocked. However as your application grows you may introduce more dependencies such as jumping or eating. So you may end up writing similar boiler plate code for each which can lead to maintenance pain and non of us want that!
What we need is easy maintenance, while still getting all the benefits of direct and straightforward dependency injection.
Lets adopt protocol composition.
protocol CanBark {
func bark()
}protocol CanWaggTail {
func waggTail()
}struct Dog {
// Protocol Composition
typealias Dependency = CanBark & CanWaggTail
let dogManager: Dependency
func ballFound() {
dogManager.waggTail()
dogManager.bark()
}
}/*----- Another Way! -----*/// Protocol Composition
protocol CanDoDogThings: CanBark, CanWaggTail {
}struct Dog {
let dogManager: CanDoDogThings
func ballFound() {
dogManager.waggTail()
dogManager.bark()
}
}
So composition can be done differently.
I like both approaches as all dependencies are now in union rather than multiple disjoint protocols:
- All the dependencies are now clearly defined.
- Single top level entry point to rule them all 😅.
- The compiler can enforce that the full protocol has been implemented.
- It overall feels cleaner and cohesive.
Explore a real world example at here.