Skip to content

Protocols & Extensions

Protocols and Extensions are core to Swift’s "Protocol-Oriented Programming" paradigm.

Protocols

A Protocol defines a blueprint of methods, properties, and other requirements. It doesn't provide the code itself, but it ensures that any type that adopts it will have certain features.

swift
protocol Identifiable {
    // { get set } means the property must be readable and writable
    // { get } would mean it only needs to be readable
    var id: String { get set }
}

struct User: Identifiable {
    var id: String // Conforms to Identifiable by providing 'id'
    var name: String
}

Why use Protocols?

Adopting a protocol like Identifiable allows you to write generic code that works with any type as long as it has an id. For example, a function could accept a list of "Identifiable" items and print their IDs, regardless of whether they are Users, Products, or Books.

Extensions

Extensions add new functionality to an existing class, struct, enum, or protocol type. This includes types for which you do not have the original source code (like built-in types).

swift
extension Int {
    func squared() -> Int {
        self * self
    }
}

print(7.squared()) // 49

Protocol Extensions

You can extend a protocol to provide a default implementation to all conforming types. This is incredibly powerful as it adds functionality to multiple types at once.

swift
extension Identifiable {
    func displayID() {
        print("The ID is: \(id)")
    }
}

// Usage Example:
let user = User(id: "USR-01", name: "Pirate")
user.displayID() // "The ID is: USR-01" -> User got this method for free!

Extensions vs. Inheritance

While both allow you to add functionality, they serve different purposes:

FeatureInheritance (Classes Only)Extensions (All Types)
Relationship"Is-a": Creates a child subclass."Skills": Adds a new ability to existing type.
StorageCan add new Stored Properties.Cannot add Stored Properties.
OverrideCan change parent behavior via override.Can only add new behavior.

Note: Extensions are the preferred way to grow your code in Swift. They keep things simple by adding "skills" without creating a messy "family tree" (inheritance).

Built-in Protocols

Swift has many powerful built-in protocols that you can adopt to make your custom types feel like native ones. Some of them are:

Equatable

Allows you to compare two instances using ==.

swift
struct Point: Equatable {
    var x: Int, y: Int
}

let a = Point(x: 1, y: 2)
let b = Point(x: 1, y: 2)
print(a == b) // true

CustomStringConvertible

Allows you to customize how your type is printed in print() or converted to a String.

swift
struct Pirate: CustomStringConvertible {
    var name: String
    var description: String { "Ahoy! I am \(name)." }
}

let p = Pirate(name: "Jack")
print(p) // "Ahoy! I am Jack."

Comparable

Allows you to use operators like <, >, and sorting.

swift
struct Score: Comparable {
    var value: Int
    static func < (lhs: Score, rhs: Score) -> Bool {
        lhs.value < rhs.value
    }
}

let high = Score(value: 100)
let low = Score(value: 50)
print(low < high) // true