Skip to content
Opaque Types and `some`
step 1/5

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() -> Shape would use existential containers — runtime polymorphism, dynamic dispatch, performance cost.
  • func makeShape() -> some Shape is 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 Protocol must return ONE concrete type — can't return Circle in one branch and Square in 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…