SyntaxStudy
Sign Up
Swift Generics and Protocol Constraints
Swift Beginner 1 min read

Generics and Protocol Constraints

Protocols with associated types (PATs) enable generic protocols. The associated type is a placeholder resolved when a concrete type conforms to the protocol. Swift 5.7 introduced primary associated types and the any and some keywords. some Protocol (opaque type) hides the concrete type while preserving type identity. any Protocol (existential) can hold any conforming type but loses type identity. Constraining generic parameters to protocols ensures the compiler can verify that all required operations are available.
Example
// Protocol with associated type
protocol Repository {
    associatedtype Entity
    func findAll() -> [Entity]
    func findById(_ id: Int) -> Entity?
    func save(_ entity: Entity)
}

struct UserRepository: Repository {
    private var users: [Int: User] = [:]

    func findAll() -> [User] { Array(users.values) }
    func findById(_ id: Int) -> User? { users[id] }
    mutating func save(_ user: User) { users[user.id] = user }
}

// some (opaque return type) - concrete type hidden but fixed
func makeRepository() -> some Repository {
    return UserRepository()
}

// Generic function constrained to protocol
func printAll<R: Repository>(_ repo: R) where R.Entity: CustomStringConvertible {
    repo.findAll().forEach { print($0) }
}

// Primary associated type (Swift 5.7+)
protocol Collection<Element> { }

// any for type-erased storage
var repos: [any Repository] = []