0
0
Swiftprogramming~15 mins

Identity comparison (===) in Swift - Deep Dive

Choose your learning style9 modes available
Overview - Identity comparison (===)
What is it?
Identity comparison (===) in Swift checks if two references point to the exact same instance of a class in memory. It is used only with class types, not with value types like structs or enums. This operator returns true if both variables refer to the same object, and false otherwise. It helps distinguish between objects that may have the same content but are different instances.
Why it matters
Without identity comparison, you could only check if two objects are equal in value, but not if they are actually the same object. This matters when you want to know if two variables share the same instance, for example, to avoid duplicating work or to manage shared resources safely. Without this, bugs could arise from mistakenly treating two different objects as one or vice versa.
Where it fits
Before learning identity comparison, you should understand Swift's basic types, classes, and value vs reference types. After this, you can learn about equality comparison (==), reference counting, and memory management. This concept fits into understanding how Swift handles objects and memory.
Mental Model
Core Idea
Identity comparison (===) checks if two variables point to the exact same object in memory, not just if they look the same.
Think of it like...
It's like checking if two people are actually the same person by looking at their ID card, not just if they wear the same clothes or have the same name.
Object A ──────┐
                │
                │
Variable x ──────┼───> [Same Object Instance]
                │
Variable y ──────┘

If x === y, both point to the same box (object). If not, they point to different boxes.
Build-Up - 6 Steps
1
FoundationUnderstanding Reference Types
🤔
Concept: Introduce what reference types are and how they differ from value types.
In Swift, classes are reference types. When you assign an instance of a class to a variable, the variable holds a reference (like an address) to the object in memory. Changing the object through one variable affects all variables that reference it. This is different from value types like structs, where each variable has its own copy.
Result
Variables can share the same object, meaning changes via one variable reflect in others.
Understanding reference types is key to grasping why identity comparison exists and when it matters.
2
FoundationDifference Between Equality and Identity
🤔
Concept: Explain the difference between checking if objects are equal in value versus if they are the same instance.
Equality (==) checks if two objects have the same content or value. Identity (===) checks if two variables point to the exact same object in memory. For example, two different instances of a class can have identical properties but are not identical objects.
Result
You learn that equality and identity are related but distinct concepts.
Knowing this difference prevents confusion when comparing objects and helps choose the right operator.
3
IntermediateUsing === Operator in Swift
🤔Before reading on: do you think === works with structs or only classes? Commit to your answer.
Concept: Introduce the syntax and usage of the identity operator (===) in Swift, emphasizing it works only with class instances.
The identity operator (===) compares two class instances to see if they are the same object. For example: class Person {} let a = Person() let b = a let c = Person() print(a === b) // true print(a === c) // false This operator cannot be used with structs or enums because they are value types.
Result
You can check if two variables refer to the same object instance.
Understanding the limitation to class types helps avoid compiler errors and misuse.
4
IntermediatePractical Uses of Identity Comparison
🤔Before reading on: do you think identity comparison is useful only for debugging or also in production code? Commit to your answer.
Concept: Show real scenarios where identity comparison is necessary, such as caching, avoiding duplicate work, or managing shared resources.
Imagine you have a cache of objects and want to avoid loading the same object twice. Using === lets you check if an object is already loaded. Another example is when you want to detect if two variables share the same instance to avoid unintended side effects when modifying one. Example: if object1 === object2 { print("Same instance") } else { print("Different instances") }
Result
You see how identity comparison helps manage object references safely and efficiently.
Knowing when to use identity comparison improves program correctness and performance.
5
AdvancedIdentity vs Equality in Custom Classes
🤔Before reading on: do you think overriding == affects === behavior? Commit to your answer.
Concept: Explain how custom equality (==) can be defined independently from identity (===), and why both are important.
You can override the == operator in your class to define when two objects are equal in value. However, this does not change identity comparison. For example: class Person: Equatable { var name: String init(name: String) { self.name = name } static func == (lhs: Person, rhs: Person) -> Bool { return lhs.name == rhs.name } } let p1 = Person(name: "Alice") let p2 = Person(name: "Alice") p1 == p2 // true (same name) p1 === p2 // false (different instances) This distinction allows you to compare content separately from identity.
Result
You understand that identity and equality serve different purposes and can coexist.
Recognizing this distinction helps avoid bugs where objects look equal but are different instances.
6
ExpertIdentity Comparison and Memory Management
🤔Before reading on: do you think identity comparison affects Swift's reference counting? Commit to your answer.
Concept: Explore how identity comparison interacts with Swift's Automatic Reference Counting (ARC) and object lifecycle.
Swift uses ARC to track how many references point to an object. Identity comparison (===) checks if two references point to the same object but does not change reference counts. However, understanding identity helps debug retain cycles and memory leaks, because you can detect if multiple variables hold the same instance unexpectedly. For example, if two variables reference the same object, modifying one affects the other, and ARC keeps the object alive until all references are gone.
Result
You gain insight into how identity relates to memory management and debugging.
Knowing this connection helps diagnose complex bugs related to object lifetime and shared references.
Under the Hood
At runtime, Swift stores class instances in heap memory and variables hold pointers (references) to these memory addresses. The identity operator (===) compares these pointers directly to check if they are equal, meaning both variables point to the same memory location. This is a fast, pointer-level comparison, unlike equality (==) which may involve custom logic.
Why designed this way?
Swift separates identity and equality to give developers precise control. Identity comparison is simple and efficient for checking if two references are the same object, which is important for reference types. Equality can be customized for value comparison. This design avoids confusion and allows flexibility in how objects are compared.
┌─────────────┐       ┌─────────────┐
│ Variable A  │──────▶│ Object #123 │
└─────────────┘       └─────────────┘

┌─────────────┐       ┌─────────────┐
│ Variable B  │──────▶│ Object #123 │
└─────────────┘       └─────────────┘

Identity check (A === B) compares pointers:
Are both pointing to Object #123? Yes → true

If Variable C points to Object #456:

┌─────────────┐       ┌─────────────┐
│ Variable C  │──────▶│ Object #456 │
└─────────────┘       └─────────────┘

A === C? No → false
Myth Busters - 4 Common Misconceptions
Quick: Does 'a === b' mean 'a == b' is always true? Commit to yes or no.
Common Belief:If two variables are identical (===), they must also be equal (==).
Tap to reveal reality
Reality:Identity (===) means same instance, but equality (==) can be false if equality is customized or not implemented. Conversely, two different instances can be equal in value but not identical.
Why it matters:Assuming identity implies equality can cause logic errors, like skipping updates because you think objects are equal when they are not.
Quick: Can you use === to compare structs? Commit to yes or no.
Common Belief:You can use identity comparison (===) with any type, including structs and enums.
Tap to reveal reality
Reality:Identity comparison only works with class instances (reference types). Structs and enums are value types and do not have identity.
Why it matters:Trying to use === with value types causes compiler errors and confusion about how data is stored and compared.
Quick: Does identity comparison affect reference counting? Commit to yes or no.
Common Belief:Using === changes the reference count of objects involved.
Tap to reveal reality
Reality:Identity comparison only checks pointers and does not modify reference counts or object lifetimes.
Why it matters:Misunderstanding this can lead to incorrect assumptions about memory management and object lifecycle.
Quick: If two variables point to the same object, can modifying one affect the other? Commit to yes or no.
Common Belief:If two variables are identical (===), changing one does not affect the other because they are separate copies.
Tap to reveal reality
Reality:If two variables are identical, they reference the same object, so changes via one variable are visible through the other.
Why it matters:Ignoring this can cause bugs where changes unexpectedly propagate, leading to hard-to-find errors.
Expert Zone
1
Identity comparison is a pointer comparison and thus very fast, but it only applies to reference types, so understanding Swift's type system deeply is crucial.
2
Overriding equality (==) does not affect identity (===), so both must be considered when designing classes that will be compared or stored in collections.
3
Using identity comparison can help detect retain cycles and memory leaks by revealing unexpected shared references in complex object graphs.
When NOT to use
Avoid using identity comparison with value types like structs or enums; use equality (==) instead. Also, do not rely solely on identity for logical equality checks in your app's domain logic; implement custom equality when needed.
Production Patterns
In production, identity comparison is used in caching mechanisms, singleton pattern implementations, and when managing shared mutable state to ensure operations affect the intended object instance. It is also used in debugging tools to detect reference sharing and memory issues.
Connections
Equality comparison (==)
Complementary concept; identity checks if two references are the same object, equality checks if two objects have the same value.
Understanding identity helps clarify why equality can be customized separately and why both are needed for robust object comparison.
Reference counting (ARC)
Identity comparison works on references managed by ARC, which tracks object lifetimes.
Knowing how identity relates to ARC helps diagnose memory management issues and understand object lifecycles.
Pointer comparison in low-level programming
Identity comparison is a high-level abstraction of pointer equality used in systems programming languages.
Recognizing identity comparison as pointer equality connects Swift's safety features with underlying memory concepts in languages like C.
Common Pitfalls
#1Trying to use === with structs causes errors.
Wrong approach:let a = 5 let b = 5 print(a === b) // Error: '===' cannot be applied to two 'Int' values
Correct approach:let a = 5 let b = 5 print(a == b) // true
Root cause:Confusing value types with reference types and misunderstanding that identity comparison only applies to class instances.
#2Assuming two identical objects are equal in value without checking equality.
Wrong approach:if a === b { print("Objects are equal") }
Correct approach:if a == b { print("Objects are equal") }
Root cause:Mixing up identity (same instance) with equality (same value) leads to incorrect logic.
#3Modifying one variable thinking it won't affect another identical reference.
Wrong approach:class Box { var value = 0 } let x = Box() let y = x x.value = 10 print(y.value) // Expect 0 but prints 10
Correct approach:Use separate instances if independent state is needed: let x = Box() let y = Box() x.value = 10 print(y.value) // 0
Root cause:Not realizing that identical references point to the same object, so changes affect all references.
Key Takeaways
Identity comparison (===) checks if two variables point to the exact same class instance in memory, not just if they have equal content.
It only works with reference types (classes), not value types like structs or enums.
Equality (==) and identity (===) are different; equality compares content, identity compares object references.
Understanding identity helps manage shared state, avoid bugs, and debug memory issues in Swift programs.
Misusing identity comparison or confusing it with equality leads to common bugs and compiler errors.