Generic Parameters and Arguments

Generics let you write code that works over many types while staying type-safe. This reference covers the grammar that makes that possible: the generic parameter clause that declares type parameters, the constraints that restrict them, where clauses, and the argument clause that supplies concrete types.

Generic parameter clause

A generic parameter clause follows a declaration's name and lists one or more type parameters in angle brackets. Each parameter is a placeholder type usable throughout the declaration.

func swapValues<T>(_ a: inout T, _ b: inout T) { ... }
struct Pair<First, Second> { let first: First; let second: Second }

Type constraints

A type constraint in the parameter clause requires a parameter to inherit from a class or conform to a protocol (or protocol composition). Write it as T: Constraint, separating multiple parameters with commas.

func max<T: Comparable>(_ xs: [T]) -> T? { xs.max() }
struct Cache<Key: Hashable, Value> { ... }

Generic where clauses

A where clause expresses constraints that the bracket syntax cannot — in particular, requirements on a parameter's associated types and same-type requirements written with ==. It appears after the signature (or after an associated type, or on an extension).

func allEqual<C: Collection>(_ c: C) -> Bool
    where C.Element: Equatable { ... }

extension Array where Element == String {
    func joinedWithCommas() -> String { joined(separator: ", ") }
}

Constraints in the parameter clause and in a where clause are equivalent in power for protocol conformance; the where form is required for associated-type and same-type requirements. You can also attach a where clause to a single member (a contextual where) so it applies only to that method or subscript.

Tip: the lightweight some Collection<Int> syntax is sugar for a generic parameter plus a same-type constraint on the primary associated type — handy when a full where clause would be overkill.

Generic argument clause

A generic argument clause supplies concrete types to a generic type at the point of use, in angle brackets after the type name. It applies to types, not functions — for generic functions, the compiler infers the type arguments from the call.

let scores = Dictionary<String, Int>()
let pair = Pair<Int, String>(first: 1, second: "a")
let doubled = swapValues(&x, &y)   // T inferred — no argument clause

Note: [Int] and [String: Int] are shorthand for the argument clauses Array<Int> and Dictionary<String, Int>.

Summary

The generic parameter clause introduces placeholder types and their inline constraints; where clauses add associated-type and same-type requirements that the bracket syntax can't express; and the generic argument clause plugs concrete types into generic types at the use site (with inference handling generic functions). Together they give Swift generics that are both flexible and fully type-checked.