sean woodward sean woodward -4 years ago 195
Swift Question

What is the proper way to reference a static variable on a Swift Protocol?

Assume a protocol defined below:

protocol Identifiable {
static var identifier: String { get }
}
extension Identifiable {
static var identifier: String { return "Default Id" }
}


What is the best way to reference the static variable? The example below illustrates two ways to access the variable. What is the difference, and is the
type(of:)
better?

func work<I: Identifiable>(on identifiable: I) {
let identifier: String = I.identifier
print("from Protocol: \(identifier)")

let identiferFromType: String = type(of: identifiable).identifier
print("using type(of:): \(identiferFromType)")
}

struct Thing: Identifiable {
static var identifier: String { return "Thing" }
}

work(on: Thing())

Answer Source

In the example you show, there is no difference. Because identifier is a protocol requirement, it will be dynamically dispatched to in both cases, therefore you don't need to worry about the wrong implementation being called.

However, one difference arises when you consider the value of self inside the static computed property when classes conform to your protocol.

self in a static method/computed property is the metatype value that it's is called on. Therefore when called on I, self will be I.self – which is the static type that the compiler infers the generic placeholder I to be. When called on type(of: identifiable), self will be the dynamic metatype value for the identifiable instance.

In order to illustrate this difference, consider the following example:

protocol Identifiable {
    static var identifier: String { get }
}

extension Identifiable {
    static var identifier: String { return "\(self)" }
}

func work<I : Identifiable>(on identifiable: I) {
    let identifier = I.identifier
    print("from Protocol: \(identifier)")

    let identiferFromType = type(of: identifiable).identifier
    print("using type(of:): \(identiferFromType)")
}

class C : Identifiable {}
class D : C {}

let d: C = D()

// 'I' inferred to be 'C', 'type(of: d)' is 'D.self'.
work(on: d)

// from Protocol: C
// using type(of:): D

In this case, "which is better" completely depends on the behaviour you want – static or dynamic.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download