Search code examples
swiftprotocolscomparable

Swift comparable on a protocol


Happy new year everyone

protocol Birthday {
    var date: Date { get set }
}
    
class Person: Birthday {
    var date: Date
    var fullName: String

    // ...
}

class Car: Birthday {
    var date: Date
    var color: UIColor

    // ...
}

I want this to conform to Comparable, so I can do

Person() > Car()

Instead of

Person().date > Car().date

How can I do that? thank you so much


Solution

  • You can do > trivially. Just write the following top-level function:

    func > (lhs: Birthday, rhs: Birthday) -> Bool { lhs.date > rhs.date }
    

    But you cannot conform Birthday to Comparable. Comparable requires that a type implement the following:

    static func < (lhs: Self, rhs: Self) -> Bool
    

    Self is the type that conforms to the protocol. Protocols do not conform to themselves. They are not "types." They describe types. (In some cases, an implicit existential type may be generated, but existential types cannot be manipulated in Swift.) To be comparable, a type must be able to compare itself to another thing of the same type, and you cannot get that with a protocol.

    But any particular syntax you would like with your protocol you can create. You just need to write the functions.

    While there is a technical limitation here (protocols don't conform to themselves), even if Swift syntax could support protocols conforming to themselves (and there are ways it could in the future), you still should never implement Comparable this way. Comparable requires Equatable. And a Person can never be Equatable to a Car. That's because Equatable requires more than a == function. It requires substitutability. If two things are "equal" in the Equatable sense, then the system can always substitute one for the other and you can never care which one it gives you. And that can't be true with with people and cars.

    To avoid this kind of problem, would not recommend using < here. It implies that there is exactly one sensible ordering for these things, and "birthdate" isn't the one only order for these things. So I would definitely recommend just being explicit and comparing the dates if you want to compare dates.