‘==’ vs ‘===’ in Swift

The difference between == and === in Swift is:

  • == checks if two values are equal.
  • === checks if two objects refer to the same object.
Difference between == and === illustrated

Also, the == operator is overridable for custom types, meanwhile === is not.

In this guide, you are going to take a look at what these differences mean and what gives rise to them in Swift.

== Operator in Swift

The double-equals operator (==) in Swift is used to check if two values are equal.

For example:

let num1 = 2
let num2 = 2

print(num1 == num2)

Output:

true

Now, let’s try to apply the triple equals === operator between the two integers:

print(num1 === num2)

This shows an error:

main.swift:24:12: error: binary operator '===' cannot be applied to two 'Int' operands
print(num1 === num2)

The === is a meaningless operation between two integers. This is because each integer object in Swift is always unique. In other words, no two variables can point to the same integer object in memory.

This kind of unique object is called value type in Swift.

Value Types in Swift

A value type is a type that is any type implemented with struct or enum.

For instance, arrays, strings, integers, and dictionaries are all value types in Swift.

A value type keeps a unique copy of its data. When you copy a value type, that is, assign it, initialize it, or pass it as an argument, you create an independent instance.

For example, if we create integers a and b, and assign a to b, we get two independent integer objects:

var a = 1
var b = a

You can verify this by changing the value in a and seeing what happens to b.

a = 100

print(a)
print(b)

Output:

100
1

This is probably something you also expected. Only the value in a was changed.

To support understanding, let’s see another example by creating a Fruit structure:

struct Fruit {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

Fruit is a value type because it was created using struct.

Now, similar to the previous example, let’s create two Fruit objects where one is assigned to the other:

var fruit1 = Fruit("Banana")
var fruit2 = fruit1

This creates two independent Fruit objects, fruit1 and fruit2.

You can verify this by changing the name of one of the fruits and seeing how it does not affect the other:

fruit1.name = "Apple"

print(fruit1.name)
print(fruit2.name)

Output:

Apple
Banana

Now you understand what is a value type in Swift. You now know that each value type object has a unique memory location. No two variables can reference the same object.

Next, let’s take a look at how to compare custom value types.

Overload == for Value Types

Let’s continue with the Fruit structure and the objects fruit1 and fruit2 described above.

Now, let’s compare these two Fruit objects using the == operator:

print(fruit1 == fruit2)

This results in an error:

main.swift:15:14: error: binary operator '==' cannot be applied to two 'Fruit' operands
print(fruit1 == fruit2)

This happens because the Fruit structure has no idea what == means.

However, you can give meaning to the == operator by overloading the == function outside the Fruit structure.

For example, let’s make Fruit objects support == operator to check if two Fruit objects have the same name:

struct Fruit {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

func ==(rhs: Fruit, lhs: Fruit) -> Bool {
    return rhs.name == lhs.name
}

Now you can make sure it works:

var fruit1 = Fruit("Banana")
var fruit2 = Fruit("Apple")

print(fruit1 == fruit2)

Output:

false

As you can see, the comparison returned false because the names of the fruits are different.

Now you understand what is a value type and how to make comparisons between two value types using the double equals == operator. You also learned that the triple-equals === operator does not work with value types.

Next, let’s jump into triple equals operator (===) and reference types in Swift.

=== Operator and Reference Types in Swift

In Swift, the === operator checks if two objects point to the same object in memory. This is completely different from the == operator that checks if two values are equal.

To understand why using === is necessary, you need to first understand what is a reference type in Swift.

Reference Type in Swift

In Swift, classes are reference types.

Unlike value types, reference types are always referenced by variables. It is possible to have an instance referenced by multiple variables and constants.

When you “copy” a reference type, you are essentially creating a shared object to which both variables point.

Let’s see an example. Here is a simple Fruit class:

class Fruit {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

It is almost identical to the Fruit structure you saw earlier. The only difference is it is a class. In other words, Fruit is a reference type instead of a value type.

Now, let’s create a Fruit object called fruit1. Then let’s create fruit2 to which we assign fruit1:

var fruit1 = Fruit("Banana")
var fruit2 = fruit1

Because classes are reference types in Swift, now both fruit1 and fruit2 point to the same Fruit object in memory. In essence, fruit1 and fruit2 are aliases that reference the same object in memory.

Two variables point to same object

If you now change the name of the fruit1, the name of the fruit2 also changes and vice versa.

fruit1.name = "Apple"

print(fruit1.name)
print(fruit2.name)

Output:

Apple
Apple

Now, there is another way to verify reference-type objects point to the same object. This is by using the === operator.

The === operator checks if two reference type variables point to the same object in memory.

For example, let’s check if the two Fruit objects reference the same object in memory:

var fruit1 = Fruit("Banana")
var fruit2 = fruit1

print(fruit1 === fruit2)

Output:

true

Now you understand how the === operator works in Swift classes and why it is important.

Earlier with custom value types, you learned that it is possible to overload the == operator. This is also the case for reference types.

Override == for a Custom Class

Let’s see what happens when we call == between the two Fruit objects:

print(fruit1 == fruit2)

This results in an error:

main.swift:20:14: error: binary operator '==' cannot be applied to two 'Fruit' operands
print(fruit1 == fruit2)

This happens because the Swift compiler has no idea what == means in the context of Fruit objects. This is the same that happened with the Fruit structure in the value type example.

With classes, it is also possible to give meaning to the == operator.

To do this, overload the == operator for the Fruit class by implementing the == function outside the class.

For example, let’s make the Fruit class support comparisons for checking if two Fruit objects have the same name.

class Fruit {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

func ==(rhs: Fruit, lhs: Fruit) -> Bool {
    return rhs.name == lhs.name
}

Now you can compare two Fruit objects:

var fruit1 = Fruit("Banana")
var fruit2 = Fruit("Apple")

print(fruit1 == fruit2)

Output:

false

Now that the names of the Fruit instances are different, the comparison yields false as expected.

This concludes the guide!

Summary

Today you learned what is the difference between == and === operators in Swift.

To recap:

  • The == operator checks if two values are equal. For custom types you can overload this operator to support comparisons.
  • The === operator checks if two variables point to the same object in memory. You cannot overload this operator for custom types.

For value types, === is a meaningless operator. This is because two instances can never refer to the same object in memory.

For reference types, === is a meaningful operation because an object can be referenced by multiple variables.

To specify what happens with custom objects and == operator, you need to overload the == function outside the class/struct.

Thanks for reading.

Happy coding!

Scroll to Top