Opaque and Existential Types
22.1 Opaque Types (some)
some means "a specific type chosen by the implementation." It preserves type identity and is statically dispatched and fast.
protocol Animal { func speak() -> String }
struct Dog: Animal { func speak() -> String { "Woof" } }
struct Cat: Animal { func speak() -> String { "Meow" } }
func makePet() -> some Animal { Dog() } // the caller doesn't know the concrete type, but it's FIXED
func describe(_ pet: some Animal) { print(pet.speak()) } // = generic parameter shorthand (Swift 5.7)
var body: some View { Text("Hello") } // SwiftUI uses opaque return types everywhere22.2 Existential Types (any)
One fixed (hidden) type Can vary at runtime Static dispatch, no boxing Existential box, dynamic dispatch Associated types / Self ✅ fully usable
Limited (opened when passed to generics) Prefer some (or generics). Use any when you truly need heterogeneity. Swift 6 requires explicit any for existentials (in Swift 6 language mode).
var pets: [any Animal] = [Dog(), Cat()] // heterogeneous: each element can be a different type
for pet in pets { print(pet.speak()) }
func feed(_ pet: any Animal) {} // a box holding any conforming type (dynamic dispatch)22.3 Opening Existentials
func printAll<T: Animal>(_ pet: T) { print(pet.speak()) }
let something: any Animal = Cat()
printAll(something) // the existential is implicitly opened (Swift 5.7)