What is generic specialization? When does it not happen?
Mental model. Specialization is the compiler making a custom copy of a recipe for your exact ingredients instead of following a generic cookbook.
Specialization clones a generic function for a concrete T, replacing witness-table calls with direct calls and enabling inlining. It happens aggressively inside a module, especially with whole-module optimization or @inlinable.
It may not happen across module boundaries unless the function is @inlinable, for any P existentials, or when the optimizer cannot see the concrete type. That is why stdlib generic == on an array is fast, while your any Equatable helper is not.
Common traps
- “The compiler always specializes.” Only when it knows the concrete type at the call site or can see the body.
- “
@inlinablemakes everything faster.” It exposes your body to clients, bloats binaries, and locks in implementation details you then cannot change.
They might follow up with
- How do you verify specialization? Look at SIL (
swiftc -emit-sil) or profile; the generic call disappears and becomes a direct call. - What is devirtualization? The same idea for class methods:
final,private, or WMO proof that no override exists.
Related questions
- 1.4.1 Generics vs protocols as types: when do you write <T: P>(T) vs any P?
- 1.7.4 What are @usableFromInline and @inlinable in relation to access control?
- 1.11.1 Static vs dynamic dispatch in Swift?
- 1.11.2 Why does final (and whole-module optimization) help performance?
← What is an existential container? What is a witness table?