iOS Interview Guide: Equatable Protocol

Nitin Aggarwal
Swiftable
Published in
7 min readFeb 12, 2024

--

Level: Intermediate, Priority: Medium

Equatable protocol is not just a fundamental aspect of the Swift, but also a crucial topic to preparing for interviews. Be ready to prepare these questions for your iOS interviews as these are the most common questions for interviews.

Q1: What is the Equatable protocol?

A type that can be compared for value equality.

protocol Equatable

The Equatable protocol is used to provide a way to compare two instances of a type for equality. It requires you to implement the == operator, which defines how instances of your type (including custom types) should be compared for equality. This is particularly useful when you have custom types and you need to compare them in the code.

Q2: How do you make a custom type conform to the Equatable protocol? Explain with an example.

For example, you’re making an app (called Task Manager) that manages a list of tasks. You have a Task struct that represents a task with a title and a priority level.

In order to implement the feature to a new task, you may need to check the task with the same title is already exists or not in your list. You want to compare tasks based on their title and priority level to check for equality.

Here's how you would use Equatable in this case:

struct Task: Equatable {
var title: String
var priority: Int

static func ==(lhs: Task, rhs: Task) -> Bool {
return lhs.title == rhs.title && lhs.priority == rhs.priority
}
}

The Task struct represents a task in the Task Manager app. It has two properties title and priority. By adding Equatable to the Task, we are indicating that instances of the Task struct can be compared for equality.

We provide a custom implementation for the == operator. This implementation defines how two instances of Task should be compared for equality. It checks whether the title and priority properties of both instances are equal. If they are, it returns true, indicating that the two tasks are equal; otherwise, it returns false.

let task1 = Task(title: "Implement login feature", priority: 1)
let task2 = Task(title: "Implement login feature", priority: 1)

if task1 == task2 {
print("Tasks are equal")
} else {
print("Tasks are not equal")
}

// print: Tasks are equal

Here, we create two Task instances: task1 and task2, with the same title and priority. We then use the == operator to compare them. Since both instances have the same title and priority, the comparison returns true.

Q3: Why == operator is overridden as static method with Equatable protocol?

static func ==(lhs: Task, rhs: Task) -> Bool {
return lhs.title == rhs.title && lhs.priority == rhs.priority
}

The equality comparison is often considered a type-level (Task in this case) operation rather than an instance-level operation. This means that it makes sense for the equality operator to be associated with the type itself rather than with individual instances of the type. By defining it as a static method, you indicate that it’s a function of the type (Task in this case) , not of any specific instance.

When comparing two instances for equality, you usually need access to their properties. Since static methods don’t have access to instance properties, they take the instances as parameters. This allows them to compare the properties of the instances passed to them.

Inside the == method, you define the logic for comparing the two instances (lhs and rhs). Typically, you compare the properties of the instances that determine their equality. In the Task example, we compare the title and priority properties of both lhs and rhs.

Q4: Why is it important to conform to the Equatable protocol for custom types?

It allows us to define what equality means for instances of a custom type. Without Equatable conformance, comparing instances of the type might lead to ambiguity or unexpected behavior. But how?

In many scenarios, such as sorting, filtering, or removing duplicates from collections, Swift relies on the Equatable protocol to determine equality. By conforming to Equatable, you ensure that your custom types behave correctly in these contexts.

Even, many Swift APIs and third-party libraries depend on types being Equatable for functionality such as data manipulation, persistence, or networking.

Q5: How equality is differ from identity when using Equatable protocol?

When we talk about equality, we are comparing the values or contents of two instances to determine if they are the same. When a type conforms to the Equatable protocol, it provides a way to compare two instances of that type to see if their values are equal. This comparison is typically done using the == operator, which checks if the properties of the instances are equal.

let a = 5
let b = 5
if a == b {
print("a and b are equal")
}

Identity refers to the memory address or location of an instance in memory. It determines whether two references point to the same instance, rather than comparing the values contained within those instances. Identity comparison is done using the === operator.

let array1 = [1, 2, 3]
let array2 = array1
if array1 === array2 {
print("array1 and array2 refer to the same instance")
}

Equatable focuses on the content or value of instances, while identity focuses on their memory addresses.

Q6: Can Equatable be used with enums? If so, how would you implement it?

Yes, the Enums can conform to the Equatable protocol by implementing the == operator to define how instances of the enum should be compared for equality.

Note: Enums are automatically made equatable if all their associated values are equatable. Swift automatically synthesizes the Equatable conformance.

Suppose we have an enum called Color representing different colors, and we want to compare colors based on their RGB values. In this case, we would need to manually implement Equatable because we're comparing associated values that are not automatically Equatable.

enum Color {
case red(Int, Int, Int)
case green(Int, Int, Int)
case blue(Int, Int, Int)
}

extension Color: Equatable {

static func ==(lhs: Color, rhs: Color) -> Bool {
switch (lhs, rhs) {
case let (.red(r1, g1, b1), .red(r2, g2, b2)):
return r1 == r2 && g1 == g2 && b1 == b2

case let (.green(r1, g1, b1), .green(r2, g2, b2)):
return r1 == r2 && g1 == g2 && b1 == b2

case let (.blue(r1, g1, b1), .blue(r2, g2, b2)):
return r1 == r2 && g1 == g2 && b1 == b2

default:
return false
}
}
}

let color1 = Color.red(255, 0, 0)
let color2 = Color.red(255, 0, 0)

if color1 == color2 {
print("Colors are equal")
} else {
print("Colors are not equal")
}

// print: Colors are equal

Since the RGB values are associated values and not automatically Equatable, we need to implement the Equatable protocol manually. We compare two colors by checking if their associated RGB values are equal.

Q7: Explain the difference between Equatable and Comparable protocols.

Both often used together to provide comprehensive comparison capabilities for custom types. But they are different:

Equatable Protocol:

  • It allows instances of a type to be compared for equality.
  • Conforming to Equatable requires implementing the == operator.
  • It is useful when you need to determine whether two instances are equal or not.
struct Task: Equatable {
var title: String
var priority: Int

static func ==(lhs: Task, rhs: Task) -> Bool {
return lhs.title == rhs.title && lhs.priority == rhs.priority
}
}

let task1 = Task(title: "Implement login feature", priority: 1)
let task2 = Task(title: "Implement login feature", priority: 1)

if task1 == task2 {
print("Tasks are equal")
} else {
print("Tasks are not equal")
}

// print: Tasks are equal

Comparable Protocol:

  • It allows instances of a type to be compared and ordered.
  • Conforming to Comparable requires implementing the less-than operator (<) and the equal-to operator (==).
  • It is useful when you need to sort or establish an order between instances of your type.
struct Student {
let name: String
let grade: Int
}

extension Student: Comparable {
static func < (lhs: Student, rhs: Student) -> Bool {
lhs.grade < rhs.grade
}
}

let student1 = Student(name: "Alice", grade: 90)
let student2 = Student(name: "Bob", grade: 95)

if student1 > student2 {
print("\(student1.name) has a higher grade than \(student2.name).")
} else {
print("\(student2.name) has a higher grade than \(student1.name).")
}

// print: Bob has a higher grade than Alice.

Differences:

  • The main difference lies in their purpose: Equatable is for determining equality, while Comparable is for establishing an order.
  • Equatable requires implementing the == operator, while Comparable requires implementing the < or == operator. Additionally, to conform to Comparable fully, you might also implement <=, >, and >= operators.
  • Equatable doesn’t imply any specific order between instances, while Comparable does by requiring a specific order relation.

In this article, I tried to cover all possible questions based on Equatable protocol. This will definitely help you to prepare for your interview.

iOS Interview Handbook

Grab your copy today and embark on your journey to iOS interview mastery with:
-
270+ top interview questions covering a wide range of topics
- Expert guidance and a complete roadmap for interview preparation
- Exclusive access to personalized one-on-one session to ask your queries

Cheers!

--

--

Nitin Aggarwal
Swiftable

Lead Software Engineer (iOS), Technical Writer, Technical Interviewer, Helping you to crack your iOS interview.