How do I use the Comparable protocol in Swift? In the declaration it says I'd have to implement the three operations <, <= and >=. I put all those in the class but it doesn't work. Also do I need to have all three of them? Because it should be possible to deduce all of them from a single one.
3 Answers
The Comparable protocol extends the Equatable protocol -> implement both of them
In Apple's Reference is an example from Apple (within the Comparable protocol reference) you can see how you should do it: Don't put the operation implementations within the class, but rather on the outside/global scope. Also you only have to implement the <
operator from Comparable
protocol and ==
from Equatable
protocol.
Correct example:
class Person : Comparable {
let name : String
init(name : String) {
self.name = name
}
}
func < (lhs: Person, rhs: Person) -> Bool {
return lhs.name < rhs.name
}
func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name
}
let paul = Person(name: "Paul")
let otherPaul = Person(name: "Paul")
let ben = Person(name: "Ben")
paul > otherPaul // false
paul <= ben // false
paul == otherPaul // true

- 4,670
- 1
- 28
- 41

- 14,673
- 7
- 45
- 62
-
How do I do this in playground? – Van Du Tran Nov 16 '14 at 22:59
-
4I don't get how this is considered 'implemented' when the actual code isn't in the class at all... Shouldn't the == < and all the rest be inside the class? Yet when I try that I get errors.. Do you know what I'm failing to understand? – fjlksahfob Nov 26 '14 at 15:06
-
5@fjlksahfob the reason is because it's adding an extension to the operator at a scope outside the class. You could even do something like `func == (lhs: ClassA, rhs: ClassB) -> Bool` if you wanted, to compare two different classes (from testing it appears to only work in the direction specified, so you would also have to create `func == (lhs: ClassB, rhs: ClassA) -> Bool`). In other words, the Swift compiler interprets `(X == Y)` as `==(X, Y)` and not `X.==(Y)` – Oliver Mar 17 '15 at 04:31
-
When you ctrl-click `Comparable` the definition tells you need to implement `==`, `>=` and `>` which leads to a compile time error. I guess this is a documentation error from Apple? Your way works. I submitted a bug report. – qwerty_so Apr 14 '15 at 12:37
-
Finally the first language that provides a Comparable interface with operator overloading. It's annoying to have both operator overloading and CompareTo methods in C# and have to use the pesky CompareTo all the time. – Pavel Jul 20 '15 at 10:14
-
@paulpaul1076 Swift isn't the first one for sure, Haskell for example, which has also influenced Swift a lot. I get your point though, it's really nice to have custom operator overloading :D – Kametrixom Jul 20 '15 at 10:20
-
1@Kametrixom, oh, cool, I haven't used Haskell, so I don't know, thanks for enlightening me. And C# does have custom operator overloading, but for sorting you use the IComparable interface, and compare by doing a.CompareTo(b) < 0, which means a < b. Why not just Make IComparable have the < operator instead? That was my point. Swift looks nice. – Pavel Jul 20 '15 at 10:31
-
1In Swift 5, I found that I didn't need to conform to equatable or implement `==` when conforming to Comparable. I implemented only `<`, and was still able to test for equality. Is it just being clever about re-using `<` with swapped arguments? – Barry Jones Jan 10 '20 at 19:10
-
What if we do not implement == from Equatable protocol? In the documentation, Apple says that we need to conform to the Equatable protocol and Comparable protocol, but when I test in the playground without Equatable I can test >= operator ?! – Hrvoje Feb 11 '22 at 09:34
Here is an update of Kametrixom's answer for Swift 3:
class Person : Comparable {
let name : String
init(name : String) {
self.name = name
}
static func < (lhs: Person, rhs: Person) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name
}
}
Instances of the Person
class can then be compared with the relational operators as follows:
let paul = Person(name: "Paul")
let otherPaul = Person(name: "Paul")
let ben = Person(name: "Ben")
print(paul > otherPaul) // false
print(paul <= ben) // false
print(paul == otherPaul) // true

- 30,049
- 21
- 112
- 147

- 3,241
- 10
- 41
- 61
To implement Swift's Comparable
protocol, you need to conform to the Equatable
protocol first by implementing static func == (lhs: Self, rhs: Self) -> Bool
, then implementing the only required function static func < (lhs: Self, rhs: Self) -> Bool
for Comparable
.
Instead of declaring global operator overloads, you should instead implement the protocol conforming methods within the struct/class itself. Although global operator overloads satisfy the protocol conformance, it's bad practice to declare them that way instead of the intended static methods on the struct/class.
If you look at the documentation example, you will see that the same is shown as sample code.
I would instead write the following:
class Person: Comparable {
let name: String
init(name: String) {
self.name = name
}
static func < (lhs: Person, rhs: Person) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name
}
}
or even separate out the protocol conformance out of the class declaration like so:
class Person {
let name: String
init(name: String) {
self.name = name
}
}
extension Person: Comparable {
static func < (lhs: Person, rhs: Person) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name
}
}
which would probably be closer to production level code.

- 5,506
- 2
- 26
- 43