Swift Conditional Conformance
Conditional conformance lets a generic type conform to a protocol only when its placeholder types meet requirements. The conformance therefore depends on the types that fill the placeholders.
A Pair that is Equatable when its values are
The Pair struct stores two values with separate placeholders. The extension makes Pair conform to Equatable only when both placeholder types conform to Equatable.
struct Pair<First, Second> {
var first: First
var second: Second
}
extension Pair: Equatable where First: Equatable, Second: Equatable {
}
let first = Pair(first: 1, second: "one")
let second = Pair(first: 1, second: "one")
let third = Pair(first: 2, second: "one")
print(first == second)
print(first == third)A Box that is Equatable when its content is
The Box struct stores one value of the placeholder type T. The extension makes Box conform to Equatable only when T conforms to Equatable.
struct Box<T> {
var value: T
}
extension Box: Equatable where T: Equatable {
}
let first = Box(value: 5)
let second = Box(value: 5)
let third = Box(value: 6)
print(first == second)
print(first == third)A Group that is Equatable when its members are
The Group struct stores an array of members. The extension makes Group conform to Equatable only when the member type conforms to Equatable.
struct Group<Member> {
var members: [Member]
}
extension Group: Equatable where Member: Equatable {
}
let first = Group(members: [1, 2, 3])
let second = Group(members: [1, 2, 3])
let third = Group(members: [1, 9, 3])
print(first == second)
print(first == third)A nested Pair uses the same conformance
Each value here is a Pair whose first value is another Pair. The inner Pair conforms to Equatable conditionally, so the outer Pair can also conform to Equatable.
struct Pair<First, Second> {
var first: First
var second: Second
}
extension Pair: Equatable where First: Equatable, Second: Equatable {
}
let left = Pair(first: Pair(first: 1, second: 2), second: "x")
let right = Pair(first: Pair(first: 1, second: 2), second: "x")
let other = Pair(first: Pair(first: 1, second: 9), second: "x")
print(left == right)
print(left == other)Example
struct Pair<First, Second> {
var first: First
var second: Second
}
extension Pair: Equatable where First: Equatable, Second: Equatable {
}
let left = Pair(first: "Ana", second: 10)
let right = Pair(first: "Ana", second: 10)
let other = Pair(first: "Ana", second: 12)
print(left == right)
print(left == other)Key points
- Conditional conformance is declared in an extension of the generic type.
- The extension names the protocol and adds a where clause with the requirements.
- A Pair of Equatable values can conform to Equatable, because both stored values can be compared.
- The synthesized comparison compares the stored values in order.
- A nested generic value can use the same conformance when its inner values also meet the requirements.
In this example, a Pair holds a String value and an Int value, and both types conform to Equatable. The first comparison prints true because both stored values match. The second comparison prints false because the second values differ.
Note
When a placeholder type fails a requirement, the generic type does not gain that conformance for that filling.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A generic type conforms to Equatable only when its placeholder type conforms to Equatable. What is this called?