Opaque Type is a Swift mechanism that allows a function to return a value of some type without revealing the concrete type to the calling code. The some keyword in the return type is the most famous example: some View in SwiftUI means “the function returns some type that conforms to View, but which one is an implementation detail.” An opaque type preserves type identity (unlike a protocol as a type), which allows the compiler to optimize the code and guarantees consistency of the returned type. According to Swift Book, 2025, opaque types solve the problem of protocols with associated types, allowing functions to return values of such protocols.
Key Takeaways
Opaque Type is a return type declared with the some keyword that hides the concrete implementation from the calling code. The caller only knows that the returned value conforms to a certain protocol, but does not know exactly which type stands behind some. Meanwhile, the compiler knows the exact type and uses it for static dispatch and optimization.
Before the introduction of opaque types in Swift 5.1 (SE-0244), it was impossible to return a protocol with associated types from a function without a boxing wrapper. For example, the Equatable protocol has an associated type, and a function could not simply return Equatable — the compiler would throw an error “protocol can only be used as a generic constraint.” Opaque type solved this problem.
func makeInt() -> some Equatable {
return 42
}
func makeString() -> some Equatable {
return "Hello"
}
// Compiler knows makeInt returns Int
// makeInt() == makeString() — ❌ error, different types
Both functions return some Equatable, but the concrete types are different: Int and String. Attempting to compare them with == will cause a compilation error because an opaque type guarantees that a specific call returns the same type, but not across different functions. This is a feature, not a bug: opaque type preserves type identity where a protocol as a type (any Equatable) loses it.
Generic and Opaque Type are two sides of the same coin. Generics let the calling code choose the type, while opaque type lets the function hide the type from the calling code. The difference is in the direction of control.
| Characteristic | Generic | Opaque some |
|---|---|---|
| Who chooses the type | Calling code | Function/method |
| Type identity | Preserved (stable) | Preserved (stable) |
| Number of return branches | One (via generic) | Same type in all branches |
| Usage | Algorithms, data structures | SwiftUI, factory methods |
In a generic function, the caller decides which type to use. The function must work with any T that satisfies the constraints. For opaque type, the caller does not know the concrete type — the implementation makes the decision.
// Generic: caller chooses type
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)
// Opaque: function hides type
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()
The choice between generic and opaque type depends on intent. If the calling code should choose the type, use generics. If the function should hide implementation details, use some. SwiftUI chose some View precisely because body should be flexible internally but stable externally.
some is a Swift keyword introduced in Swift 5.1 (SE-0244). It is used in return position to declare an opaque type, as well as in parameters (SE-0341) and properties. some guarantees that the concrete type is stable and known to the compiler but hidden from external code.
Starting with Swift 5.7, some can be used not only in return position but also in parameters. some Equatable in a parameter means “this function accepts any Equatable type, but all calls inside a specific body see the same type.”
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
// a and b — potentially different types, == won't work directly
return isEqual(a, b)
}
func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
return a == b
}
Using some in parameters provides a more concise syntax compared to
any is a Swift 5.6+ keyword for explicitly declaring existential types (protocol as a type). Unlike some, any erases type identity: the compiler does not know which concrete type hides behind the protocol. This provides flexibility (you can store different types in a single array), but at the cost of performance.
some — static polymorphism: the compiler knows the concrete type, uses direct dispatch, and can inline code. any — dynamic polymorphism: a virtual method table (existential container) is used, which adds indirection.
protocol Drawable {
func draw()
}
// some: static type is known
func makeDrawable() -> some Drawable {
return Circle() // Single return type
}
// any: dynamic, can store different types
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())
The choice between some and any is a trade-off between performance and flexibility. Some is faster but limits to a single implementation. Any is more flexible (you can mix types) but slower due to dynamic dispatch. In SwiftUI, body always uses some View because each View’s body is one concrete type.
Opaque Type solves a fundamental Swift problem: protocols with associated types (PAT) cannot be used directly as a type. A function cannot simply return Collection — the compiler requires specifying Element. some Collection resolves this by hiding the associated type.
Without opaque type, returning a Collection would require using a concrete type (Array
func makeReversedCollection<T>(
of array: [T]
) -> some Collection {
return array.reversed()
}
let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
print(item)
}
result can be iterated, but you cannot directly access ReversedCollection properties. This protects encapsulation: if you later replace reversed() with another method using a different implementation, the calling code won’t break. Opaque type gives you the freedom to change the implementation without changing the API.
some View is the most famous use of opaque type. Every View in SwiftUI declares body as some View. This means body returns some concrete type of View, but the developer does not need to think about exactly what it is — TupleView, Group, ModifiedContent, or any other type from the framework.
Without opaque type, body would have to return a concrete type, for example, ModifiedContent<Button<Text>, Padding>, which is impractical. some View hides this complexity. The compiler infers the exact type of body automatically at compile time.
struct ContentView: View {
var body: some View {
VStack {
Text("Hello")
.font(.title)
Button("Tap me") {
print("Tapped")
}
}
.padding()
}
}
The compiler infers body as ModifiedContent<VStack<TupleView<(Text, Button<Text>)>>, Padding>. The developer sees some View. If you change the layout from VStack to HStack, the compiler will automatically re-infer the type — no manual edits needed. This is the magic of opaque type: the developer focuses on interface logic, not on composition types.
Frequently Asked Questions
Opaque Type is a type declared with the some keyword that hides the concrete implementation from the calling code. The compiler knows the exact type, but the developer using the function only sees the protocol.
some is an opaque type with static identity: the compiler knows the concrete type. any is an existential type with dynamic dispatch: type identity is erased. Some is more performant, any is more flexible.
some View hides the complex concrete type of body, which the compiler infers automatically. This frees the developer from having to write the exact type consisting of generic wrappers (VStack, Group, ModifiedContent).
Yes, starting with Swift 5.7. Some in parameters is syntactic sugar over a generic parameter. It simplifies function declarations, especially when working with protocols where each some-parameter does not require a separate
The compiler will throw an error: opaque type requires all return branches to return the same concrete type. This is intentional to preserve type identity. If you need to return different types, use any.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also