What is generic specialization? When does it not happen?

1.4.7 · L5 · Learning

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.
  • “@inlinable makes 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?