Comparing in Swift
The whole world is obsessed with comparison. Lebron vs. Jordan, Obama vs. Putin, Viper vs. Mountain, iOS vs. Android, and the list goes on. Let’s indulge ourselves in this perverse pleasure of comparison for a bit here. Say we want to compare The Dark Knight with Man of Steel. We can start by creating a class that stores movie information.
class Movie {
let name: String
var tomatometer: Int
init(name: String, tomatometer: Int = 0) {
self.name = name
self.tomatometer = tomatometer
}
}
Now let’s compare.
let darkKnight = Movie(name: "Dark Knight", tomatometer: 94)
let manOfSteel = Movie(name: "Man of Steel", tomatometer: 56)
if manOfSteel < darkKnight {
println("The Dark Knight is a better movie than Man of Steel.")
}
Swift gets angry at us when we start comparing things willy-nilly. It shows us a rather cryptic message: Cannot invoke ‘>’ with an argument list of type ‘(Movie, Movie)’. Perhaps, it’s trying to warn us that “comparison is the thief of joy” as Theodore Roosevelt did. But we choose to ignore the words of wisdom and pursuade Swift to allow us to compare. Our weapon of persuasion happens to be the Comparable protocol.
class Movie : Comparable {
let name: String
var tomatometer: Int
init(name: String, tomatometer: Int = 0) {
self.name = name
self.tomatometer = tomatometer
}
}
func < (lhs: Movie, rhs: Movie) -> Bool {
return lhs.tomatometer < rhs.tomatometer
}
func == (lhs: Movie, rhs: Movie) -> Bool {
return lhs.name == rhs.name
}
We don’t need to work too hard to satisfy Swift’s needs as far as comparison is concerned. All we need to do is implement <
and ==
operators. Swift will provide implementations for the rest: <=
, >=
, and >
.
Did you notice that we had to provide declarations for
<
and==
at global scope? Weird, huh? The declarations aren’t inside theMovie
class because these operators aren’t supposed to be called as methods like this:manOfSteel.< darkKnight
.
By the way, Comparable
protocol itself inherits from two other protocols.
protocol Comparable : _Comparable, Equatable {
func <=(lhs: Self, rhs: Self) -> Bool
func >=(lhs: Self, rhs: Self) -> Bool
func >(lhs: Self, rhs: Self) -> Bool
}
protocol _Comparable {
func <(lhs: Self, rhs: Self) -> Bool
}
protocol Equatable {
func ==(lhs: Self, rhs: Self) -> Bool
}
As it turns out, the two operators (<
and ==
) we were required to implement above come from _Comparable
and Equatable
protocols. Now the following code should print “The Dark Knight is a better movie than Man of Steel.” in the console.
if manOfSteel < darkKnight {
println("The Dark Knight is a better movie than Man of Steel.")
}
Swift now allows us to do following comparisons as well.
if manOfSteel <= darkKnight {
println("Didn't I already tell you The Dark Knight is better?")
}
if manOfSteel == darkKnight {
println("Are you insane?")
}
if manOfSteel >= darkKnight {
println("No way!!")
}
if manOfSteel > darkKnight {
println("I think you're losing your mind.")
}
Let’s stop before we get addicted to this game of comparison.