Reading — step 1 of 5
Learn
~1 min readBuilders and Opaque Types
some declares an opaque return type — "this returns SOMETHING that satisfies this protocol, but I'm not telling you what."
protocol Shape {
func area() -> Double
}
struct Circle: Shape {
let radius: Double
func area() -> Double { 3.14 * radius * radius }
}
// Returns a Shape — but the caller doesn't know which kind
func makeShape() -> some Shape {
return Circle(radius: 5)
}
Why not Shape directly?
func makeShape() -> Shapewould use existential containers — runtime polymorphism, dynamic dispatch, performance cost.func makeShape() -> some Shapeis static — the compiler knows the concrete type, gives you the protocol's interface, but the type is opaque to callers.
This is the SwiftUI View trick:
struct ContentView: View {
var body: some View { // some specific concrete type — VStack<...>
VStack {
Text("Hello")
Button("Tap") { }
}
}
}
SwiftUI's body returns some View so the compiler can specialize but you don't write the absurd nested generic types.
Constraints:
- A function returning
some Protocolmust return ONE concrete type — can't returnCirclein one branch andSquarein another. - For multiple types, use
any Protocol(the existential):
func makeShape(kind: String) -> any Shape {
if kind == "circle" { return Circle(radius: 5) }
return Square(side: 4)
}
some vs any:
some Protocol— opaque, single concrete type, fast (static dispatch)any Protocol— existential, can hold any conforming type, slower (dynamic dispatch)
Use some when you can. Use any when you genuinely need heterogeneous collections or runtime polymorphism.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…