Swift Generics
Swift generics let you write flexible, reusable functions and types that work with any type while preserving full type safety.
What Are Generics?
Without generics, you'd need a separate function for every type you want to support — one to swap two integers, another to swap two strings, and so on. Generics let you write the logic once using a placeholder type, conventionally named T, and the compiler fills in the real type at each call site.
Swap Two Values
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temporary = a
a = b
b = temporary
}
var first = 10
var second = 42
swapValues(&first, &second)
print(first, second) // 42 10
var nameOne = "Alice"
var nameTwo = "Bob"
swapValues(&nameOne, &nameTwo)
print(nameOne, nameTwo) // Bob AliceWriting Generic Functions
A generic function can take multiple type parameters, and you can constrain them to protocols so the compiler knows which operations are legal. Below, T is restricted to Equatable, which guarantees the == operator exists for whatever concrete type is used.
Generic Search Function
func firstIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
for (index, element) in array.enumerated() {
if element == value {
return index
}
}
return nil
}
let numbers = [5, 12, 8, 19, 3]
if let position = firstIndex(of: 19, in: numbers) {
print("Found at index \(position)") // Found at index 3
}
let words = ["swift", "kotlin", "rust"]
print(firstIndex(of: "rust", in: words) ?? -1) // 2Generic Types
Generics aren't limited to functions — structs, classes, and enums can also be generic. A generic Stack<Element> works identically whether Element is Int, String, or a custom model type, and the compiler still enforces that you never mix types within one instance.
A Generic Stack
struct Stack<Element> {
private var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element? {
return items.popLast()
}
var top: Element? {
return items.last
}
var isEmpty: Bool {
return items.isEmpty
}
}
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
print(intStack.pop() ?? 0) // 3
var stringStack = Stack<String>()
stringStack.push("first")
stringStack.push("second")
print(stringStack.top ?? "") // secondConstraining Type Parameters
- Equatable — allows values of T to be compared with == and !=
- Comparable — enables ordering with <, >, <=, and >=
- Hashable — lets T be stored in a Set or used as a Dictionary key
- Numeric — restricts T to numeric types so arithmetic operators are available
Exercise: Swift Generics
What core problem do generics solve in Swift?