Search code examples
swiftclassgenericsstaticprotocols

Given an instance of a Swift object, can we test its class for the presence of a class function?


I've looked around, and haven't seen an answer to my question (but maybe I should be able to infer one).

I have an object, based on a protocol. It's an associated type protocol, with class operators that are defined, based on the type assigned to associatedtype, like so:

protocol GenericBaseProtocol {
    associatedtype T

    var myProperty: T {get set}
    init(_ myProperty: T )
}

extension GenericBaseProtocol where T: Equatable {
    static func ==(lhs: Self, rhs: Self) -> Bool {
        return lhs.myProperty == rhs.myProperty
    }
}

So if I create a class, based on this, and give T an Equatable type, like so:

class IntClass: GenericBaseProtocol {
    typealias T = Int
    var myProperty: T = 0

    required init(_ myProperty: T ) {
        self.myProperty = myProperty
    }
}

The resulting object should be comparable, like so:

let lhs = IntClass(3)
let rhs = IntClass(4)

let isEqual = lhs == rhs

Cool. Now, if I then create an instance with a non-Equatable type, like so:

class ArrayClass: GenericBaseProtocol {
    typealias T = [String]
    var myProperty: T = []

    required init(_ myProperty: T ) {
        self.myProperty = myProperty
    }
}

And instantiate that, like so:

let lhs2A = ArrayClass(["HI"])
let rhs2A = ArrayClass(["Howaya"])

I will have compile-time syntax errors when I try this:

let isEqual = lhs2A == rhs2A

What I'd like to be able to do, is test the class object of lhs2A, and see if it implements static func ==(lhs: Self, rhs: Self) -> Bool

I'm not sure this can be done, but it would be nice for this article I'm writing up if I could add a runtime/guard proof to the playground, instead of simply commenting out the code.

Any ideas?


Solution

  • You could extend your protocol to give it a default implementation for the == operator in cases where the associated type is not Equatable.

    This could also be used to provide a runtime indicator of wether the type is equatable or not.

    for example:

    extension GenericBaseProtocol where T: Equatable {
        static func ==(lhs: Self, rhs: Self) -> Bool {
            return lhs.myProperty == rhs.myProperty
        }
        var isEquatable:Bool { return true }
    }
    
    extension GenericBaseProtocol {
        static func ==(lhs: Self, rhs: Self) -> Bool {
            return false
        }
        var isEquatable:Bool { return false }
    }