Kotlin Tutoial

Basics

Control Flow

Array & String

Functions

Collections

OOPs Concept

Exception Handling

Null Safety

Regex & Ranges

Java Interoperability

Miscellaneous

Android

Equality evaluation in Kotlin

In Kotlin, equality evaluations are performed differently than in some other languages, like Java. There are two types of equality:

  1. Structural Equality (==): Checks the data or contents of the variables.
  2. Referential Equality (===): Checks if two references point to the same object in memory.

Let's delve deeper into each type and understand them better:

1. Structural Equality (== and !=)

Kotlin uses the == operator to compare the data or contents of variables (i.e., it calls the equals() function behind the scenes). If you come from a Java background, this is different from Java's ==, which checks for referential equality.

In Kotlin:

data class Person(val name: String, val age: Int)

val person1 = Person("Alice", 30)
val person2 = Person("Alice", 30)

println(person1 == person2)  // Outputs: true
println(person1 != person2)  // Outputs: false

In the example above, even though person1 and person2 are different objects, the == operator checks their structural equality and returns true since both objects have the same content.

For custom non-data classes, you may want to override the equals() method to provide your own definition of structural equality.

2. Referential Equality (=== and !==)

The === operator checks if two references point to the same object in memory. This is similar to the == operator in Java when applied to objects.

Using the previous Person class:

val person3 = person1

println(person1 === person2)  // Outputs: false
println(person1 === person3)  // Outputs: true
println(person1 !== person2)  // Outputs: true

While person1 and person2 are structurally equal, they are different objects in memory. On the other hand, person3 is just another reference to the same object as person1, so person1 === person3 is true.

3. equals() function:

The equals() function checks for structural equality. It's called when you use the == operator. For data classes, Kotlin automatically generates the equals() function. However, for custom classes, you might need to override it for a meaningful structural comparison.

class Rectangle(val length: Int, val breadth: Int) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as Rectangle
        if (length != other.length) return false
        if (breadth != other.breadth) return false
        return true
    }
}

Conclusion:

Understanding equality evaluations in Kotlin is essential for writing correct and efficient code. Always be clear about which type of equality you want to check:

  • Use == (or !=) for structural equality.
  • Use === (or !==) for referential equality.

When implementing your own classes, ensure you override the equals() method responsibly, especially if you want a custom structural equality check.

Kotlin equality operators (== and ===)

Description: The == operator checks for structural equality, while the === operator checks for referential equality.

Code:

val a: String = "Hello"
val b: String = "Hello"
val c: String? = a

println(a == b)  // true (structural equality)
println(a === b) // true (referential equality)
println(a === c) // true (referential equality)

How to compare objects for equality in Kotlin

Description: Use the == operator for structural equality. Custom classes can override the equals method.

Code:

class Person(val name: String, val age: Int)

val person1 = Person("Alice", 25)
val person2 = Person("Alice", 25)

println(person1 == person2) // true (structural equality)

Kotlin equals() and hashCode() methods

Description: The equals() method is used for structural equality, and hashCode() is used for hash-based collections.

Code:

data class Book(val title: String, val author: String)

val book1 = Book("Kotlin in Action", "Dmitry Jemerov")
val book2 = Book("Kotlin in Action", "Dmitry Jemerov")

println(book1 == book2) // true (structural equality)
println(book1.hashCode() == book2.hashCode()) // true

Data classes and equality in Kotlin

Description: Data classes automatically provide equals() and hashCode() methods based on their properties.

Code:

data class Point(val x: Int, val y: Int)

val point1 = Point(1, 2)
val point2 = Point(1, 2)

println(point1 == point2) // true (structural equality)

Structural equality in Kotlin

Description: Structural equality (==) compares the content of objects.

Code:

val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2, 3)

println(list1 == list2) // true (structural equality)

Referential equality vs structural equality in Kotlin

Description: Referential equality (===) checks if two references point to the same object.

Code:

val a: String = "Hello"
val b: String = "Hello"

println(a === b) // false (different references)

Comparing strings in Kotlin

Description: String comparison using == and ===.

Code:

val str1: String = "Hello"
val str2: String = "Hello"
val str3: String? = str1

println(str1 == str2)  // true (structural equality)
println(str1 === str2) // true (referential equality)
println(str1 === str3) // true (referential equality)

Customizing equality in Kotlin

Description: Custom classes can override equals() for custom equality checks.

Code:

class Circle(val radius: Double)

override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (other !is Circle) return false

    return this.radius == other.radius
}

Equality for collections in Kotlin

Description: Collections use structural equality for comparison.

Code:

val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2, 3)

println(list1 == list2) // true (structural equality)

Kotlin compareTo() function

Description: The compareTo() function is used for ordering elements.

Code:

data class Person(val name: String, val age: Int) : Comparable<Person> {
    override fun compareTo(other: Person): Int {
        return this.age.compareTo(other.age)
    }
}

val person1 = Person("Alice", 25)
val person2 = Person("Bob", 30)

println(person1 < person2) // true

Overriding equals() and hashCode() in Kotlin

Description: Override equals() and hashCode() for custom classes.

Code:

class CustomClass(val property1: String, val property2: Int) {
    override fun equals(other: Any?): Boolean {
        // Custom equality logic
    }

    override fun hashCode(): Int {
        // Custom hash code logic
    }
}

Kotlin equality for nullable types

Description: Nullable types use == for structural equality and === for referential equality.

Code:

val a: String? = "Hello"
val b: String? = "Hello"
val c: String? = null

println(a == b)  // true (structural equality)
println(a === b) // false (different references)
println(a == c)  // false (structural equality)

Kotlin objects and identity comparison

Description: Object references can be compared for identity using ===.

Code:

val obj1 = Any()
val obj2 = obj1

println(obj1 === obj2) // true (referential equality)

Equality in Kotlin for primitive types

Description: Primitive types use == for structural equality.

Code:

val x: Int = 5
val y: Int = 5

println(x == y) // true (structural equality)