Background:
In Swift before version 5, when returning a value conforming to a protocol with associated types, developers often faced limitations — the type couldn't be used as a return type directly, requiring type erasure. To improve readability and performance, opaque types were introduced — return values using the keyword some, allowing to describe abstractions in public interfaces.
Problem:
When it's necessary to hide the actual type of the return value, while maintaining abstraction through the protocol, but also avoiding the overhead of dynamic dispatch and type erasure. For instance, when returning collections, sequences, view components.
Solution:
Opaque types allow returning a type conforming to a protocol while hiding its concrete implementation. The compiler knows the actual type, but the calling side does not.
Example:
protocol Shape { func area() -> Double } struct Circle: Shape { var radius: Double func area() -> Double { Double.pi * radius * radius } } func makeCircle() -> some Shape { return Circle(radius: 3) } let s = makeCircle() print(s.area()) // works
Key features:
someHow does an opaque type (some Protocol) differ from a return type Protocol?
An opaque type has a concrete implementation at compile-time (although hidden externally). When returning Protocol, dynamic dispatch occurs, and there is no type safety if there are associated types.
Can different types be returned using some Protocol in one function?
No. All returns must return the same concrete type:
func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // Error: return type does not match } }
Can associated type inside Protocol be used through some Protocol?
Yes. This is precisely what opaque types are for:
protocol View { associatedtype Body } func makeView() -> some View { /* ... */ }
A function returns a protocol without opaque, preventing the use of methods with associated types, requiring complex type erasure, code fails to compile or works suboptimally.
Pros:
Cons:
ViewBuilder in SwiftUI uses some View, hiding details, increasing type safety, improving compilation speed and runtime.
Pros:
Cons: