Inheritance Rules
Protocols can refine other protocols. A type that conforms to the refined protocol automatically owes the requirements of the parent.
Refinement
protocol Equatable {
func isEqual(to other: Self) -> Bool
}
protocol Comparable: Equatable {
func compare(other: Self) -> Ordering
}
Comparable refines Equatable. A type conforming to Comparable must satisfy both — isEqual and compare. Anywhere a type parameter is constrained to Equatable, a Comparable type satisfies it.
Combining protocols
A protocol can inherit from many. Stack them:
protocol Sortable: Comparable, Hashable {
// Sortable's own requirements, if any
}
A Sortable type satisfies Comparable, Hashable, and anything Sortable adds.
Composition without naming
When a function needs more than one capability and you don't want to invent a new protocol, list them:
protocol Drawable {
func draw()
}
func process[T](item: T) where T: Drawable, T: Hashable { /* ... */ }
Same effect as creating a protocol DrawableAndHashable: Drawable, Hashable {}, without the bookkeeping.
When to refine, when to compose
- Refine when the relationship is permanent and meaningful —
Comparabletypes are alwaysEquatable. - Compose at the use site when you just happen to need two capabilities for one function.
Don't invent intermediate protocols just to give a name to a where clause.