Protocol extension vs inheritance for default behaviour — what are the tradeoffs?
Mental model. An extension method is a bicycle attached to the contract. If the contract does not mention it, nobody is required to use your bicycle.
An extension adds methods without adding a vtable or witness-table entry unless the method is also a protocol requirement. If it is only in the extension, calls through any P or through a concrete type resolve statically to the extension's implementation.
So: if you need dynamic dispatch and overriding, declare the method in the protocol and provide a default in an extension. If you only need shared helper logic, an extension is fine — just do not expect it to be overridden.
| protocol extension | superclass | |
|---|---|---|
| Structs and enums | yes | no |
| Several sources | yes, many protocols | no, single inheritance |
| Stored state | no | yes |
| Overrides dispatch dynamically | only for requirements | yes |
| Call the parent version | no | super |
Common traps
- “Adding a default in an extension makes it overridable.” Only if it is a requirement. This is the single most common protocol bug in production code.
- Believing the override is dead code. It is not — it is called when the static type is the concrete type, which makes the bug maddeningly intermittent.
They might follow up with
- How do you prove it? Call the method through
any Pand through the concrete type; you will get different implementations. - What about a class conforming to a protocol with an extension method? Same rule — no witness entry, no override.
Related questions
- 1.4.6 What is an existential container? What is a witness table?
- 1.3.1 What can live in a protocol? What can live in an extension?
- 1.11.3 You added a method in a protocol extension and overrode it on a concrete type, but calling through any P does…
← What is protocol-oriented programming, and when does it fail? Why might collection.map call the stdlib generic overload instead of… →