Introduction

Swift Docs - Associated Types

Swift is a language that lets you write code in different ways, such as object-oriented, functional, and protocol-oriented. One of the features that makes Swift protocol-oriented is the ability to use associated types in protocols.

What are associated types in Swift protocols?

Associated types are a way to use placeholder types in protocols. Placeholder types are types that you don’t know yet, but you will know later when you use the protocol. Associated types let you write generic protocols that can work with different types that have the same requirements.

For example, suppose you want to write a protocol that represents a stack. A stack is a data structure that stores items in a last-in first-out (LIFO) order. You can add items to the top of the stack and remove items from the top of the stack. You can also check how many items are in the stack and if the stack is empty.

You could write a protocol like this:

protocol Stack {
    // define an associated type called Element
    associatedtype Element
    
    // define a method to add an element to the top of the stack
    mutating func push(_ element: Element)
    
    // define a method to remove and return an element from the top of the stack
    mutating func pop() -> Element?
    
    // define a property to get the number of elements in the stack
    var count: Int { get }
    
    // define a property to check if the stack is empty
    var isEmpty: Bool { get }
}

In this example, we have defined a protocol called Stack that has an associated type called Element. The Element type represents the type of the elements that the stack can store. However, we don’t know what the Element type is exactly; we leave it as a placeholder that will be decided by the types that use the protocol.

How to use associated types in Swift protocols?

To use associated types in Swift protocols, you need to do two things:

  • Define an associated type in your protocol using the associatedtype keyword
  • Specify the actual type for the associated type in your protocol conformance using the typealias keyword or by inference

For example, suppose we want to make an array conform to the Stack protocol. We could write something like this:

// make Array conform to Stack
extension Array: Stack {
    // specify the actual type for Element using typealias
    //optional we can omit typealias and let Swift infer Element from Element
    typealias Element = Element
    
    // implement the required methods and properties
    mutating func push(_ element: Element) {
        self.append(element)
    }
    
    mutating func pop() -> Element? {
        return self.popLast()
    }
    
    var count: Int {
        return self.count
    }
    
    var isEmpty: Bool {
        return self.isEmpty
    }
}

In this example, we have made Array conform to Stack by extending it and implementing the required methods and properties. We have also specified the actual type for Element using typealias. In this case, we have chosen Element as the Element type, which is the generic type parameter of Array. This means that any array can be used as a stack for its elements.

Alternatively, we could omit the typealias declaration and let Swift infer the Element type from the context.

For example, suppose we want to use our Stack protocol with different datatypes, such as Int and String. We could write something like this:

// create an array of integers
var numbers = [1, 2, 3]

// use numbers as a stack of integers
numbers.push(4) // numbers is now [1, 2, 3, 4]
numbers.pop() // returns 4 and numbers is now [1, 2, 3]
numbers.count // returns 3
numbers.isEmpty // returns false

// create an array of strings
var words = ["hello", "world"]

// use words as a stack of strings
words.push("swift") // words is now ["hello", "world", "swift"]
words.pop() // returns "swift" and words is now ["hello", "world"]
words.count // returns 2
words.isEmpty // returns false

In this example, we have created two arrays of different data types: numbers and words. We have used them as stacks of integers and strings, respectively. We have used the same methods and properties defined by the Stack protocol to manipulate the stacks. This shows how associated types allow us to use the same protocol with different data types.

Conclusion

Associated types are a powerful feature of Swift that allow us to write generic protocols that can work with different types that have different actual types for their associated types. By using them wisely, we can improve our code quality, flexibility, and abstraction. Thanks for reading!