Protocol extension vs inheritance for default behaviour — what are the tradeoffs?

1.3.3 · L3 · Learning

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 extensionsuperclass
Structs and enumsyesno
Several sourcesyes, many protocolsno, single inheritance
Stored statenoyes
Overrides dispatch dynamicallyonly for requirementsyes
Call the parent versionnosuper

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 P and 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… →