# Generics, Associated Types, some and any — Swift

Source: https://www.skillbyai.com/en/swift/p-generics

> Write generic code and choose between opaque types and existentials.

## Code that works with many types

**Generics** let functions and types work with any type that meets requirements, while keeping full type safety: `func largest<T: Comparable>(_ items: [T]) -> T?`. Constraints use protocols (`T: Hashable`) and `where` clauses for more complex rules. Generic types such as `Stack<Element>` and Swift's own `Array<Element>` and `Dictionary<Key, Value>` are specialised by the compiler for performance. Protocols can declare **associated types**, placeholders filled in by conforming types (`Sequence` has an `Element`). Two keywords control how protocol types are used. **`some Protocol`** is an **opaque type**: one specific concrete type that the compiler knows but callers do not, with no runtime cost, used everywhere in SwiftUI (`var body: some View`). **`any Protocol`** is an **existential**: a box that can hold any conforming type and can change at run time, needed for heterogeneous collections (`[any Shape]`) but with some dynamic dispatch cost and restrictions. Prefer generics or `some` by default and use `any` when you truly need different types mixed together.

## Generics, constraints and some versus any

One generic function, one generic type and both protocol-type forms.

```swift
func largest<T: Comparable>(_ items: [T]) -> T? {
    guard var best = items.first else { return nil }
    for item in items.dropFirst() where item > best { best = item }
    return best
}
largest([3, 9, 4])            // Optional(9)
largest(["pear", "apple"])    // Optional("pear")

struct Stack<Element> {
    private var items: [Element] = []
    mutating func push(_ item: Element) { items.append(item) }
    mutating func pop() -> Element? { items.popLast() }
    var top: Element? { items.last }
}

protocol Shape { func area() -> Double }
struct Circle: Shape { let r: Double; func area() -> Double { .pi * r * r } }
struct Square: Shape { let side: Double; func area() -> Double { side * side } }

func makeDefaultShape() -> some Shape { Circle(r: 1) }   // opaque: one hidden concrete type
let mixed: [any Shape] = [Circle(r: 1), Square(side: 2)]  // existential: different types together
let totalArea = mixed.reduce(0) { $0 + $1.area() }

func printAreas(_ shapes: some Collection<any Shape>) {    // primary associated type
    for s in shapes { print(s.area()) }
}
```

## A sealed gift versus a mixed hamper

`some Shape` is a sealed gift: there is exactly one thing inside and the giver knows what, but you only know it is a shape. `any Shape` is a hamper that can hold a different shape in every slot, which is flexible but needs more handling.

**Quiz:** When do you need `any Protocol` rather than `some Protocol`?

- [ ] Never
- [ ] When returning from SwiftUI body
- [ ] When using generics with constraints
- [x] When values of different concrete types must be stored together, such as in [any Shape]

*Answer:* When values of different concrete types must be stored together, such as in [any Shape]. Existentials allow heterogeneous values; opaque types stand for one fixed concrete type.
