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 everywhere

22.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)