Generics vs protocols as types: when do you write <T: P>(T) vs any P?

1.4.1 · L2 · Interview

Predict first

Does this compile?

func same(_ xs: [any Equatable]) -> Bool {
    xs[0] == xs[1]
}
  • Yes
  • No

Mental model. A generic is a custom-fitted suit. An existential is a one-size-fits-all coat — it fits everything and flatters nothing.

Use generics at API boundaries you control: the compiler keeps the concrete type, specializes the function, and can inline it. Zero existential cost.

Use any P when you need heterogeneity — a stored property, an array of mixed conformers, a plugin list — or when a generic parameter would have to propagate through too much of your API.

The cost of any is real: possible boxing, indirect calls per method, and no specialization of the caller. On a hot path (scroll handler, body, parser loop) that matters.

== needs both sides to be the same concrete type, and two any Equatable values may not be. A generic <T: Equatable>([T]) guarantees it.

<T: P>some Pany P
Compiler knows the typeyesyesno
Mixed types in one arraynonoyes
Method callsspecialisedspecialisedwitness table
May box on the heapnonoyes
Self / associated typesyesyeslimited

Common traps

  • Reaching for any because generics feel noisy. The noise is one type parameter; the cost is permanent dynamic dispatch.
  • Reaching for generics everywhere. A generic parameter that is always the same concrete type is just indirection with extra steps.

They might follow up with

  • What is the “generic parameter creep” problem? One generic parameter forces every caller and wrapper to become generic too. Sometimes an existential at the boundary is the pragmatic choice.
  • Can you mix them? Yes — a generic function can take any P internally, and an existential can be opened into a generic context.

Related questions

  • 1.4.2 some View vs any View — what is the difference, and why does SwiftUI use some?
  • 1.4.4 What is the difference between some P as a parameter (Swift 5.7) and <T: P>?
  • 1.4.3 What is the cost of any vs some on a hot path?

some View vs any View — what is the difference, and why does SwiftUI… →