WWDC24 deal: 30% off our Swift and SwiftUI books! Learn more ...WWDC24 deal:30% off our Swift and SwiftUI books >>

Use cases for self, Self and Self.self in Swift

The Swift language constructs self, Self, and Self.self can sometimes be a source of confusion, even for experienced developers. It's not uncommon to pause and recall what each is referring to in different contexts. In this post I aim to provide some straightforward examples that clarify the distinct roles and uses of these three constructs. Whether it's managing instance references, adhering to protocol conformance, or accessing metatype information, understanding these concepts is key to harnessing the full potential of Swift in our projects.

# self - instance reference

self refers to the instance of the type within its own instance methods. It's a way to access the instance's properties and methods from within its own scope. This is particularly useful for differentiating between instance properties and method parameters when they share the same name.

class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
}

# Self - type reference in protocols

Self with a capital "S" refers to the type that conforms to a protocol, allowing for polymorphic behavior. It enables protocols to specify requirements that are then tailored to the conforming type, a feature that's especially powerful in the context of protocol-oriented design.

protocol Duplicatable {
    func duplicate() -> Self
}

In the Duplicatable protocol, Self is used to specify that the duplicate() method should return an instance of the conforming type. The exact type is not specified in the protocol itself, but will be determined by the type that conforms to the protocol. It allows each conforming type to have a clear contract: if you conform to Duplicatable, you must implement a duplicate() method that returns an instance of your own type.

# Self.self - metatype reference

Self.self is used to refer to the metatype of the type, essentially the type of the type itself. It's commonly used in static methods or when we need to access type-level properties or pass the type itself as a parameter.

protocol Registrable {
    static func register()
}

extension Registrable {
    static func register() {
        print("Registering \(Self.self)")
    }
}

class Service: Registrable {}

// Prints `Registering Service`
Service.register()

In this example, Self.self is used to access the metatype of the conforming type (Service) within a static method, allowing for type-level operations.

Understanding and correctly utilizing self, Self, and Self.self are fundamental in harnessing the full potential of Swift's type system and protocol-oriented programming capabilities. Each serves a specific purpose, enabling more expressive, flexible, and maintainable code.

As someone who has worked extensively with Swift, I've gathered many such insights over the years. I'm excited to share these in my new book Swift Gems. This book is packed with advanced tips and techniques to help intermediate and advanced Swift developers enhance their coding skills. From optimizing collections and handling strings to mastering asynchronous programming and debugging, "Swift Gems" provides practical advice to elevate your Swift development. Grab your copy of Swift Gems and let's explore the advanced techniques together.

Books by Natalia PanferovaBooks by Natalia Panferova
WWDC24: 30% off all books!
  • Swift Gems

    100+ tips to take your Swift code to the next level

  • Integrating SwiftUI into UIKit Apps

    A detailed guide on gradually adopting SwiftUI in UIKit projects

The offer is active until the 16th of June.