3

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

אורי orihpt
  • 2,358
  • 2
  • 16
  • 41

2 Answers2

2

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.

אורי orihpt
  • 2,358
  • 2
  • 16
  • 41
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
0

Thanks @Rob Napier for the great answer.

I want to add something - for those of you that wants to conform to Comparable to be able to sort an array, I wrote this extension:

extension Array where Element: Birthday {
    mutating func sort() {
        sort(by: { $0.date < $1.date })
    }
    
    func sorted() -> [Element] {
        return sorted(by: { $0.date < $1.date })
    }
}
אורי orihpt
  • 2,358
  • 2
  • 16
  • 41