Generics let one function or data type work with many kinds of value. Protocols say what those values must be able to do. Together, they let you reuse code without giving up type checking.
Generic functions and types
Type parameters use angle brackets:
A bound may appear inline or in a where clause:
Use && between separate predicates and & to compose protocols in one conformance bound.
Protocols
A protocol may require methods, initializers, static methods, and associated types. It may also provide default implementations:
protocol Named { func name() -> String } protocol Pet { associated Food: Named func favorite_food() -> Food func description() -> String { "a pet who likes " + self.favorite_food().name() } }
Self names the conforming type.
Extensions and conformances
An extension adds methods or declares conformance:
Generic extensions bind their parameters explicitly:
A protocol can also be extended, adding a method to every conformer that meets the extension's constraints.
Protocol arguments and associated types
Protocol arguments distinguish different conformances, as in Equatable<RHS> or Add<RHS>. Associated types describe a type selected by a conformance, as Iterator.Element does. Associated equality constraints use == in a where clause.
Protocols and generic parameters may define defaults, for example:
protocol EqualTo<RHS = Self> { func equals(_ other: RHS) -> Bool }
Existentials
any P stores a value behind an object-safe protocol interface:
Associated bindings can be written in the existential type:
typealias IntIterator = any Iterator<Element = Int>
A protocol is object-safe when its requirements keep Self in receiver position in the ways supported by the compiler. Use a generic parameter when the concrete type should remain known; use any P when different conforming types must share one runtime representation.
Static value generics
A static generic parameter is a compile-time value and participates in type identity:
Static constraints use ==, <, and <=. Type arguments accept a limited set of compile-time expressions, so types such as Matrix<N + 1, (M) * 2> are possible while type checking remains predictable.
Further reading
TalkTalk's protocols draw from type classes and qualified types:
- How to make ad-hoc polymorphism less ad hoc introduces type classes.
- A theory of qualified types develops the constraint system behind them.
- Type classes as objects and implicits compares closely related implementation strategies.
TalkTalk uses both protocol arguments and associated types. Protocol arguments versus associated types explains why they are separate features in this language.