Comparable Protocol: How to Compare Custom Objects

Swift provides powerful tools for comparing and equating custom objects using the Comparable and Equatable protocols.

In this tutorial, we will explore how to use the Comparable protocol to compare custom objects based on their properties, and the Equatable protocol to determine whether two objects are equal.

By the end of this tutorial, you will have a better understanding of how to implement these protocols in your own code and how they can be used to add functionality to your custom classes.

If you are interested in video lessons on how to write Unit tests and UI tests to test your Swift mobile app, check out this page: Unit Testing Swift Mobile App

The == Operator

The == operator in Swift is used to compare the values of two instances of a type for equality. It returns a Boolean value indicating whether the two values are equal or not. When comparing two instances of a custom class, the == operator compares the values of the instance properties of the two objects.

Here’s an example of how the == operator can be used to compare two instances of a custom class:

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let person1 = Person(name: "John", age: 30)
let person2 = Person(name: "John", age: 30)

if person1 == person2 {
    print("The two persons are equal.")
} else {
    print("The two persons are not equal.")
}

Output:

The two persons are not equal.

In this example, we create two instances of the Person class with the same values for their name and age properties. We then use the == operator to compare the two objects, which returns false because person1 and person2 reference different memory locations, even though they have the same property values.

The === Operator

The === operator in Swift is used to compare two instances of a reference type to see if they refer to the same object in memory. It returns a Boolean value indicating whether the two objects are the same or not.

Here’s an example of how the === operator can be used to compare two instances of a custom class:

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let person1 = Person(name: "John", age: 30)
let person2 = person1

if person1 === person2 {
    print("person1 and person2 refer to the same object in memory.")
} else {
    print("person1 and person2 do not refer to the same object in memory.")
}

Output:

person1 and person2 refer to the same object in memory.

In this example, we create an instance of the Person class and assign it to two different variables. We then use the === operator to compare the two variables, which returns true because they refer to the same object in memory.

Conforming a Custom Class to the Comparable Protocol in Swift

In Swift, we can make custom classes conform to the Comparable protocol to enable comparison operations such as less than (<), greater than (>), and equal to (==). By implementing the required comparison operators, we can define the logic for comparing instances of our custom class.

In this section, we’ll walk through an example of how to make a custom Friend class conform to the Comparable protocol in Swift and implement the comparison operators to compare instances of the Friend class based on their age and name properties.

import Foundation

class Friend : Comparable {
    let name : String
    let age : Int
    
    init(name : String, age: Int) {
        self.name = name
        self.age = age
    }
}

func < (lhs: Friend, rhs: Friend) -> Bool {
    return lhs.age < rhs.age
}

func > (lhs: Friend, rhs: Friend) -> Bool {
    return lhs.age > rhs.age
}

func == (lhs: Friend, rhs: Friend) -> Bool {
    var returnValue = false
    if (lhs.name == rhs.name) && (lhs.age == rhs.age) {
        returnValue = true
    }
    return returnValue
}

The code defines a custom Friend class that conforms to the Comparable protocol in Swift.

  • The Friend class has two instance properties: name and age, both of which are of type String and Int, respectively.
  • The init method is used to initialize the name and age properties with the provided values.
  • The code defines three functions that implement the comparison operators for the Friend class: <, >, and ==.
  • The < function compares the age property of the left-hand side (lhs) Friend object to the age property of the right-hand side (rhs) Friend object.
  • The > function compares the age property of the lhs Friend object to the age property of the rhs Friend object.
  • The == function checks if the name and age properties of lhs are equal to the name and age properties of rhs.
  • Because the Friend class conforms to the Comparable protocol, it is possible to use the <, >, and == operators to compare two instances of the Friend class for less than, greater than, and equal to, respectively.

Comparing Custom Objects Conforming to the Comparable Protocol in Swift

In this section, we’ll compare instances of custom classes that conform to the Comparable protocol using the comparison operators defined for the class. We’ll use the Friend class example that we defined earlier and demonstrate how the == operator can be used to compare two objects based on their properties.

let friend1 = Friend(name: "Sergey", age: 35) 
let friend2 = Friend(name: "Sergey", age: 30) 
print("\Compare Friend object. Same person? (friend1 == friend2)")

Output:

false

The code creates two instances of the Friend class, friend1 and friend2, with different age properties but the same name property. The code then uses the == operator to compare the friend1 and friend2 objects, checking if they represent the same person.

Since the == operator has been implemented for the Friend class, it checks whether the name and age properties of friend1 and friend2 are equal. In this case, since the age property is different for the two objects, the comparison returns false.

This demonstrates how we can compare instances of custom classes that conform to the Comparable protocol using the comparison operators defined for the class. In this case, we used the == operator to check if two instances of the Friend class represented the same person, based on their name and age properties.

Equatable Protocol VS Comparable Protocol

Swift provides two protocols for comparing custom types: Equatable and Comparable. While both of these protocols allow us to define custom comparison logic for our types, there are some important differences between the two that we should be aware of:

Equatable Protocol

The Equatable protocol provides a way to compare two instances of a type for equality. It requires us to implement the == operator for our custom type, which takes two instances of the type as parameters and returns a Bool value indicating whether the two instances are equal.

Here’s an example of a Person class conforming to the Equatable protocol:

class Person: Equatable {
    let name: String
    let age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
}

let person1 = Person(name: "John", age: 30)
let person2 = Person(name: "John", age: 30)
print(person1 == person2) // true

In this example, the Person class conforms to the Equatable protocol by implementing the == operator. The operator checks if the name and age properties of two instances of Person are equal, and returns true if they are.

Comparable Protocol

The Comparable protocol provides a way to compare two instances of a type and determine their relative order. It requires us to implement three comparison operators for our custom type: < (less than), > (greater than), and == (equal to).

Here’s an example of a Friend class conforming to the Comparable protocol:

class Friend: Comparable {
    let name: String
    let age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    static func < (lhs: Friend, rhs: Friend) -> Bool {
        return lhs.age < rhs.age
    }
    
    static func == (lhs: Friend, rhs: Friend) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
}

let friend1 = Friend(name: "Sarah", age: 25)
let friend2 = Friend(name: "Jack", age: 30)
print(friend1 < friend2) // true

In this example, the Friend class conforms to the Comparable protocol by implementing the < and == operators. The < operator compares the age properties of two instances of Friend and returns true if the left-hand side instance’s age is less than the right-hand side instance’s age.

Differences between Equatable and Comparable

The main difference between Equatable and Comparable is the type of comparison that they allow. Equatable is used for checking equality between two instances of a type, while Comparable is used for ordering two instances of a type relative to each other.

Additionally, while the Equatable protocol requires us to implement only the == operator, the Comparable protocol requires us to implement three comparison operators: <, >, and ==. This makes the Comparable protocol more powerful and flexible than the Equatable protocol, as it allows us to perform more complex operations like sorting and searching. However, Equatable protocol only provides a way to check if two objects are equal or not.

Furthermore, remember the following:

  • Use Equatable protocol when you only need to compare objects for equality. For example, if you have a custom class representing a user and you need to check if two user objects represent the same user, you can make the class conform to the Equatable protocol and implement the == operator.
  • Use Comparable protocol when you need to compare objects and order them based on their properties. For example, if you have a custom class representing a product and you need to sort a list of products based on their prices, you can make the class conform to the Comparable protocol and implement the < and > operators.

To summarize, both protocols allow for object comparison, but Comparable is more powerful and versatile, while Equatable is simpler and only checks for equality. It’s important to choose the appropriate protocol based on your specific use case.

Conclusion

In conclusion, this tutorial provided a comprehensive overview of the Comparable protocol in Swift, and how to use it to compare custom objects. We explored the == and === operators, as well as how to conform a custom class to the Comparable protocol. We also covered the Comparable and Equatable protocols and discussed their differences.

If you want to continue learning about Swift, make sure to visit the Swift Tutorials page. This page provides a wealth of information and resources to help you improve your Swift skills and stay up-to-date with the latest advancements in the language.

Frequently asked questions

  • What happens if I try to compare objects that do not conform to the Comparable protocol?
    If you try to compare objects that do not conform to the Comparable protocol in Swift, you will get a compile-time error. This is because the Comparable protocol provides the necessary requirements for Swift to know how to compare two objects of the same type, and if those requirements are not met, the comparison operation will not work.
  • Can I implement both the Equatable and Comparable protocols in the same custom class?
    Yes, it is possible to implement both the Equatable and Comparable protocols in the same custom class in Swift. By conforming to both protocols, you can define both equality and comparison behavior for your custom objects. However, it is important to ensure that the implementation of both protocols is consistent and does not cause any conflicts or unexpected behavior.
  • How does Swift determine the order of two objects when comparing them using the Comparable protocol?
    When comparing two objects that conform to the Comparable protocol in Swift, the order is determined by the implementation of the < (less than) and > (greater than) operators in the custom class. If the < operator returns true, then the first object is considered to be less than the second object. Conversely, if the > operator returns true, then the first object is considered to be greater than the second object. If neither the < nor the > operator returns true, then the two objects are considered to be equal.

Leave a Reply

Your email address will not be published. Required fields are marked *