What is a type eraser (AnyHashable, AnyView, AnyCancellable)? When do you write one?
Predict first
What does this print?
let a: AnyHashable = 1
let b: AnyHashable = "1"
print(a == b)
- true
- false
- Compile error
Mental model. A type eraser is a plain brown envelope: it hides what is inside so a shelf can hold envelopes of many different contents.
A type eraser is a concrete wrapper that hides a generic or associated type behind a uniform surface: AnyHashable, AnyView, AnyPublisher, AnyCancellable, AnySequence.
You write one when a public API cannot leak some/generics — most commonly to store heterogeneous conformers in one property or array. Prefer any P or primary associated types when they suffice; hand-written erasers are maintenance and add a layer of indirection.
The eraser keeps the underlying type. An Int and a String are never equal, even inside the same box.
Common traps
- Writing an eraser for every PAT. Modern Swift can often express the same thing with
any P<T>— check before adding a type. - Erasing too early.
AnyViewin SwiftUI loses identity and can force re-renders; erase only at the boundary that needs it.
They might follow up with
- How does
AnyCancellableerase anything? It wrapsCancellableso a set can hold subscriptions of any publisher type and cancel them on deinit. - What is the cost? An extra allocation and an indirect call per operation, plus lost specialization.
Related questions
- 1.3.5 What is an associated type? Why can’t you write let x: MyPAT easily?
- 1.3.6 What is a primary associated type? Give an example.
- 1.4.2 some View vs any View — what is the difference, and why does SwiftUI use some?
← What is a primary associated type? Give an example. How do you evolve a public protocol without breaking clients? →