In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Swift, the right declaration depends on what you actually want to preserve: a concrete type, a protocol contract, or an exact generic type constrained by protocols. Those are related ideas, but they are not interchangeable, and confusing them is the main reason this topic feels harder than it first appears.
Declare the Concrete Type When the Type Is Truly Known
If you already know the exact type you want to store, declare that type directly. Protocol conformance is then checked where the type is defined, not where the variable is stored.
This is the strongest and simplest declaration because the compiler knows the exact type at all times.
Use an Existential When Any Conforming Type Is Acceptable
If the variable should hold any value that conforms to one or more protocols, use an existential type with any.
Here, the variable is not specifically a Service. It is some runtime value that satisfies both protocol requirements.
This is a useful design when the caller should not depend on the exact concrete type.
Use Generics When You Need Constraints Without Type Erasure
Sometimes you want abstraction, but you also want Swift to preserve the concrete type. That is where generics are better than an existential variable.
This still requires the argument to conform to both protocols, but it does not erase the concrete type into any Named & Runnable. That difference matters when type relationships between parameters, return values, or associated types need to stay visible to the compiler.
Understand the Real Design Choice
The phrase "a specific type that conforms to protocols" often hides two different goals:
- you know the exact type and want to store that exact type
- you only care that the value matches a protocol contract
Those lead to different declarations:
- '
let x: MyConcreteTypewhen the exact implementation matters' - '
let x: any P & Qwhen any conforming type is acceptable'
Choosing between them is not just syntax. It is an API design decision about how much type information should remain available.
Protocols With Associated Types Need Extra Care
Not every protocol can be used as a simple existential variable. If a protocol has an associated type or Self requirements, you may need generics or type erasure instead.
A protocol like this cannot always be treated the way newcomers expect with a plain existential variable, because the associated type still has to mean something concrete somewhere.
That is why Swift developers often choose between three strategies:
- concrete type storage
- existential storage with
any - generic constraints for type-preserving abstraction
Use a Practical Rule of Thumb
A good everyday rule is:
- use a concrete type when implementation details matter
- use
anyprotocol composition when storage flexibility matters - use generics when you want abstraction without losing static type information
That rule solves most day-to-day confusion around protocol-based declarations.
Common Pitfalls
- Using an existential when a generic constraint is really needed.
- Forgetting
anyin modern Swift when declaring existential protocol variables. - Expecting protocol existentials to preserve concrete type relationships.
- Assuming protocols with associated types behave like simple storage types.
- Over-abstracting when a plain concrete type declaration would have been clearer.
Summary
- Declare the concrete type directly when the exact type is known and important.
- Use
any P & Qwhen the variable may hold any value conforming to multiple protocols. - Use generics when you want protocol constraints without erasing the concrete type.
- Existentials and generics solve different problems in Swift.
- Protocols with associated types often require generics or type erasure rather than a simple existential variable.

