Kotlin provides a more expressive and precise way to compare instances by supporting two types of equality checks:
- Structural Equality
- Referential Equality
These two forms of equality help distinguish between value-based and reference-based comparisons, making Kotlin a more robust language compared to many others.
1. Structural Equality (==)
Structural equality is checked through the == operator and its inverse != operator. By default, the expression containing x==y is translated into the call of equals() function for that type.
From:
x==yTo:
x?.equals(y) ?: (y === null)This states that,
- If x is not null, it calls x.equals(y).
- If x is null, it checks if y is also null using referential equality (===).
This means that == in Kotlin is null-safe and doesn't throw a NullPointerException.
Note: To use ==, the class should override the equals() method. In Kotlin, data classes automatically generate equals() (and hashCode()) based on their properties.
2. Referential Equality (===)
Referential equality checks whether two variables point to the same object in memory. The === operator is used to determine this:
x === y // true only if x and y refer to the same object instanceThe inverse operator !== checks if two references point to different instances. For types that are compiled to primitive types (like Int, Double, etc.), the === and !== operators may behave like == and !=, since primitives don't have object identity in the same way.
Structural vs Referential Equality
Example:
data class Square(val side: Int)
fun main() {
val square1 = Square(5)
val square2 = Square(5)
val square3 = square1
// Structural Equality
if (square1 == square2) {
println("Two squares are structurally equal")
} else {
println("Two squares are not structurally equal")
}
// Referential Equality
if (square1 === square2) {
println("Two squares are referentially equal")
} else {
println("Two squares are not referentially equal")
}
// Referential Equality with the same reference
if (square1 === square3) {
println("square1 and square3 refer to the same instance")
}
}
Output:
Two squares are structurally equal
Two squares are not referentially equal
square1 and square3 refer to the same instance