Associated Types
An associated type is a type member of a protocol. The protocol declares that a type exists; each conforming type picks a concrete one.
Declaring
protocol Container {
type Item
func count() -> Int
func item(at index: Int) -> Item
}
Item is a placeholder. Any type conforming to Container will choose what Item becomes.
Conforming
<!-- sample: continue -->struct Stack[T] {
var items: [T]
}
extend Stack[T]: Container {
type Item = T
public func count() -> Int { self.items.count }
public func item(at index: Int) -> T { self.items(index) }
}
The type Item = T line picks the concrete type. The declaration is explicit — Kestrel does not infer Item from the method signatures, and leaving it out is an error (E455), even though item(at:) already returns T.
Using associated types in generic code
Refer to a protocol's associated type with dotted access:
<!-- sample: continue -->func first[C](in container: C) -> Optional[C.Item] where C: Container {
if container.count() > 0 {
.Some(container.item(at: 0))
} else {
.None
}
}
C.Item is whatever the conforming type picked. first works on Stack[User] (returning Optional[User]) and Stack[Int] (returning Optional[Int]).
Constraining associated types
A where clause on an extension can constrain an associated type:
extend Container where Item: Comparable {
public func max() -> Optional[Item] {
if self.count() == 0 { return .None };
var best = self.item(at: 0);
for i in 1..<self.count() {
let candidate = self.item(at: i);
if candidate > best { best = candidate };
}
.Some(best)
}
}
max() exists only on containers whose items are Comparable. This is what lets generic code do real work: combining "the item type, whatever it is" with "and that item type can be compared."
Why bother?
The alternative would be making every protocol generic — Container[T] instead of Container { type Item }. That works but forces every consumer of the protocol to thread T through. Associated types let the protocol stay un-parameterized at the call site while still being type-safe.
A useful rule: if the type parameter is part of what the protocol means, it's an associated type. If it's part of which protocol you want, it's a generic parameter.