Swift Generics

Swift Generics

Generics are one of the most powerful features of Swift.

They allow you to write flexible, reusable functions and types that can work with any data type, subject to requirements that you define.

In fact, much of the Swift standard library is built using generic code. For example, arrays and dictionaries are generic collections!


The Problem Generics Solve

Imagine you want to write a function that swaps the values of two integers.

You write the function for Int. But later, you realize you need to swap two String values.

Without generics, you would have to write a completely new function for Strings, duplicating your logic entirely.


Generic Functions

To create a generic function, you place a placeholder type name (often <T>) inside angle brackets right after the function name.

This tells Swift that T is a placeholder for a type that will be determined when the function is actually called.

A Generic Function:

// The <T> makes this function generic
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var x = 5 var y = 10 swapTwoValues(&x, &y) print("x: \(x), y: \(y)")

Now, swapTwoValues can be used with Integers, Strings, Doubles, or any custom Structs you create!


Generic Types

You can also create your own custom generic types, like generic classes, structs, or enums.

A classic example is creating a custom Stack data structure that can hold any type of element.

A Generic Struct:

struct Stack<Element> {
    var items: [Element] = []
    mutating func push(_ item: Element) {
        items.append(item)
    }
}

// We explicitly define this stack to hold Strings var stringStack = Stack<String>() stringStack.push("First") stringStack.push("Second")

print(stringStack.items)


Type Constraints

Sometimes you don't want your generic to accept any type. You want it to only accept types that conform to a specific protocol.

You can enforce this by adding a type constraint. For example, <T: Equatable> ensures the type passed in can be compared using ==.

Type Constraints:

func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind { return index }
    }
    return nil
}

Exercise

Which syntax is used to denote a generic placeholder type in Swift?