Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A protocol extension in Swift allows you to provide default implementations for protocol requirements and inject new methods, computed properties, subscripts, and initializers into all conforming types. By extending a protocol, you define behavior globally for the protocol itself, rather than requiring each conforming type to implement the logic individually.

Syntax and Default Implementations

To extend a protocol, use the extension keyword followed by the protocol name. You can provide default implementations for methods or properties defined in the protocol, or add entirely new functionality.
import Foundation

protocol CustomIdentifiable {
    var id: String { get }
    func identify()
}

extension CustomIdentifiable {
    // Default implementation of a protocol requirement
    func identify() {
        print("ID: \(id)")
    }
    
    // New functionality not defined in the original protocol
    var isUUID: Bool {
        return UUID(uuidString: id) != nil
    }
}
When a type conforms to CustomIdentifiable, it is only required to provide the id property. The identify() method and isUUID property are automatically inherited. The conforming type can optionally provide its own definition of identify() to override the default implementation. However, if the conforming type provides its own isUUID property, it merely shadows the extension property rather than overriding it, due to how Swift handles method dispatch.

Constrained Extensions

You can restrict a protocol extension so that its default implementations and new members are only available to conforming types that meet specific conditions. This is achieved using a where clause.
protocol Container {
    associatedtype Item
    var items: [Item] { get }
}

// Extension only applies if the associated type 'Item' conforms to 'Equatable'
extension Container where Item: Equatable {
    func contains(_ item: Item) -> Bool {
        return items.contains(item)
    }
}
Constraints can be based on class inheritance, protocol conformance, or specific type equality (e.g., where Item == String).

Method Dispatch Rules

The most critical technical distinction in protocol extensions is how Swift handles method dispatch. The resolution of which method implementation to execute depends on whether the method is declared in the original protocol definition.

1. Dynamic Dispatch (Protocol Requirements)

If a method is declared in the protocol definition and provided a default implementation in the extension, Swift uses dynamic dispatch. The runtime will look up the actual underlying type of the instance and call its specific implementation, even if the variable is cast to an existential protocol type.

2. Static Dispatch (Extension-Only Methods)

If a method is not declared in the protocol definition but is added via a protocol extension, Swift uses static dispatch. The compiler determines which method to call based strictly on the variable’s declared type at compile time, ignoring the underlying instance type.
protocol Animal {
    func speak() // Protocol requirement
}

extension Animal {
    func speak() { print("Generic animal sound") } // Default implementation
    func sleep() { print("Generic sleep") }        // Extension-only method
}

struct Dog: Animal {
    func speak() { print("Woof") }
    func sleep() { print("Dog sleep") }
}

let typedAsDog: Dog = Dog()
let typedAsAnimal: any Animal = Dog()

// Dynamic Dispatch (Declared in protocol)
typedAsDog.speak()      // Prints: "Woof"
typedAsAnimal.speak()   // Prints: "Woof" (Runtime resolves to Dog's implementation)

// Static Dispatch (Not declared in protocol)
typedAsDog.sleep()      // Prints: "Dog sleep"
typedAsAnimal.sleep()   // Prints: "Generic sleep" (Compiler resolves to Animal's extension)

Memory and State Limitations

Protocol extensions cannot contain stored properties. Because protocols do not define memory layout, an extension cannot allocate memory for new state. Any properties added via a protocol extension must be computed properties.
Master Swift with Deep Grasping Methodology!Learn More