Protocol composition in Swift - Time & Space Complexity
When using protocol composition in Swift, it's important to understand how combining multiple protocols affects the time it takes to check if a type conforms to all of them.
We want to know how the time to verify protocol conformance grows as we add more protocols to the composition.
Analyze the time complexity of checking conformance to a composed protocol.
protocol A { func doA() }
protocol B { func doB() }
protocol C { func doC() }
func checkConformance(_ obj: Any) {
if let obj = obj as? A & B & C {
obj.doA()
obj.doB()
obj.doC()
}
}
This code checks if an object conforms to three protocols combined using protocol composition.
Look at what happens when Swift checks protocol conformance:
- Primary operation: Checking each protocol in the composition one by one.
- How many times: Once for each protocol in the composition (here, 3 times).
As you add more protocols to the composition, the number of checks grows directly with the number of protocols.
| Number of Protocols (n) | Approx. Checks |
|---|---|
| 3 | 3 |
| 10 | 10 |
| 100 | 100 |
Pattern observation: The time to check grows in a straight line as you add more protocols.
Time Complexity: O(n)
This means the time to check protocol composition grows proportionally with the number of protocols combined.
[X] Wrong: "Checking protocol composition is done all at once, so time stays the same no matter how many protocols there are."
[OK] Correct: Each protocol must be checked separately, so more protocols mean more checks and more time.
Understanding how protocol composition affects performance helps you write clear and efficient Swift code, a skill that shows you know how to think about code behavior beyond just making it work.
"What if the protocols in the composition had inheritance relationships? How would that affect the time complexity of checking conformance?"
Practice
protocol composition in Swift allow you to do?Solution
Step 1: Understand protocol composition concept
Protocol composition uses the & symbol to combine multiple protocols into one requirement.Step 2: Differentiate from class inheritance
Swift does not support multiple class inheritance, but protocol composition allows combining multiple protocols.Final Answer:
Combine multiple protocols into one requirement using & -> Option DQuick Check:
Protocol composition = Combine protocols with & [OK]
- Confusing protocol composition with class inheritance
- Thinking protocols can inherit from classes
- Assuming protocol composition overrides methods
Solution
Step 1: Identify correct usage of protocol composition
Protocol composition is used in type annotations likelet variable: ProtocolA & ProtocolB.Step 2: Check other options for syntax errors
Options B and C misuse protocol inheritance or assignment syntax; D tries class inheritance from protocols incorrectly.Final Answer:
let combined: ProtocolA & ProtocolB -> Option BQuick Check:
Protocol composition syntax = type annotation with & [OK]
- Trying to inherit protocols with & in protocol declaration
- Using = instead of : or &
- Using class inheritance syntax with protocols
protocol A { func foo() }
protocol B { func bar() }
struct S: A, B {
func foo() { print("foo") }
func bar() { print("bar") }
}
func test(x: A & B) {
x.foo()
x.bar()
}
let s = S()
test(x: s)Solution
Step 1: Understand protocol composition parameter
The functiontestrequires an argument conforming to both protocols A and B.Step 2: Check struct S conformance and method calls
S conforms to both A and B, so callingfoo()andbar()prints "foo" and "bar" respectively.Final Answer:
foo bar -> Option CQuick Check:
Both protocol methods called = foo and bar printed [OK]
- Assuming only one protocol's method runs
- Thinking protocol composition causes errors
- Confusing struct conformance with protocol composition
protocol P1 { func p1() }
protocol P2 { func p2() }
func doSomething(x: P1 & P2) {
x.p1()
x.p2()
}
struct MyStruct: P1 {
func p1() { print("p1") }
}
doSomething(x: MyStruct())Solution
Step 1: Check struct conformance to protocols
MyStruct conforms only to P1, missing P2 conformance.Step 2: Understand function parameter requirement
doSomething requires an argument conforming to both P1 and P2, so MyStruct instance is invalid.Final Answer:
MyStruct does not conform to P2, so cannot be passed to doSomething -> Option AQuick Check:
Protocol composition requires all protocols conformed [OK]
- Passing instance conforming to only one protocol
- Thinking protocol composition allows partial conformance
- Ignoring compiler errors about missing protocol methods
protocol Drawable { func draw() }
protocol Colorful { var color: String { get } }
struct Circle: Drawable, Colorful {
var color: String
func draw() { print("Drawing a \(color) circle") }
}
struct Square: Drawable {
func draw() { print("Drawing a square") }
}Which code snippet correctly uses protocol composition to accept only Drawable and Colorful types?
Solution
Step 1: Identify correct protocol composition syntax
func render(item: Drawable & Colorful) { item.draw() } usesDrawable & Colorfulcorrectly in parameter type.Step 2: Check other options for syntax or logic errors
func render(item: Drawable | Colorful) { item.draw() } uses | which is invalid; C misuses where clause syntax; D uses where clause incorrectly on parameter.Final Answer:
func render(item: Drawable & Colorful) { item.draw() } -> Option AQuick Check:
Use & to combine protocols in function parameters [OK]
- Using | instead of & for protocol composition
- Misusing where clauses in parameter declarations
- Trying to filter protocol properties in parameter signature
Ready to prove it?
Pass the test and this pattern moves unknown
