What is difference between == and === in kotlin
Asked Answered
G

4

22

What is the difference between the comparison operators == and === in Kotlin?

class A {
  var foo = 1
}
    
var a1 = A()
var a2 = A()
    
println(a1 == a2)  // output false
println(a1 === a2) // output false
    
a1 = a2 
       
println(a1 == a2)  // output true
println(a1 === a2) // output true
Gas answered 14/7, 2018 at 14:58 Comment(1)
Read the docs: kotlinlang.org/docs/reference/equality.htmlSisley
B
14

In Kotlin, two types of equality are available. These are: Structural Equality & Referential Equality.

class A {
  var foo = 1
}

var a1 = A()
var a2 = A()

Here a1 and a2 are two instances of class A.

println(a1 == a2)

It prints false because a1 and a2 are not structurally equal.

println(a1 === a2)

It prints false because a1 and a2 are not referencing the same object.

But, if you execute this line: a1 = a2 then,

a1 and a2 will be structurally equal and a1 is referencing to the a2 instance. That's why,

println(a1 == a2)
println(a1 === a2)

both these lines returns true.

Bobbybobbye answered 14/7, 2018 at 15:13 Comment(2)
Why are a1 and a2 not structurally equal?Sentinel
This answer is incomplete. It presents two cases in which the two operators return identical values. It would be more interesting to show a case where they differ.Decury
S
27

Briefly speaking, from the docs:

In Kotlin there are two types of equality:

  • Structural equality (a check for equals()) => ==
  • Referential equality (two references point to the same object) => ===

Detailed answer:

Structural Equality (==)

The negated counterpart of == is !=

By convention, an expression like a == b is translated to:

a?.equals(b) ?: (b === null)

if a is not null, it calls the equals(Any?) function, otherwise it checks that b is referentially equal to null.

To provide a custom equals check implementation, override the equals(other: Any?): Boolean function. Functions with the same name and other signatures, like equals(other: Foo) , don't affect equality checks with the operators == and !=.

Referential Equality (===)

The negated counterpart of === is !==

a === b evaluates to true if and only if a and b point to the same object. For values which are represented as primitive types at runtime (for example, Int ), the === equality check is equivalent to the == check.

Code explanation

Let's assume the definition of A is as you have defined in your question.

Snippet 1

>>> var a1 = A()
>>> var a2 = A()
>>> a1 == a2 // a1 and a2 are different instances of A
false
>>> a1 == a1
true
>>> a2 == a2
true
>>> a1 === a2 // a1 and a2 have references to different objects
false

For regular classes, the implementation of equals is inherited from Any, and just make the object equal to itself.

Snippet 2

>>> var a1 = A()
>>> var a2 = A()
>>> a1 = a2 
>>> a1 == a2
true
>>> a1 === a2
true

a1 and a2 point to the same object that is why a1 == a2 and a1 === a2 return true.

Snippet 3

Let's override equals(Any?) of A as follows:

class A {
    var foo = 1
    override fun equals(other: Any?): Boolean {
        if (other == null || other !is A)
            return false
        return foo == (other as A).foo
    }
}

Now let's run the following:

>>> var a1 = A()
>>> var a2 = A()
>>> a1 == a2
true
>>> a1 === a2
false

Notice that a1 and a2 are structurally equal even though they reference difference objects.

Sentinel answered 23/9, 2020 at 15:50 Comment(4)
Misleading answer! In snippet 2, a1 === a2 should be false.Pocked
@SriyankSiddhartha No that will be true, as a1 = a3 written above, so now points(reference) to same memory locationLignite
I thought the same thing as @SriyankSiddhartha at first. Snippet 2 would be less confusing if it said var a2 = a1 instead of var a2 = A(); a1 = a2, where the last statement is easy to overlook as it resembles the equality tests.Biquadrate
Regarding "For regular classes, the implementation of equals is inherited from Any, and just make the object equal to itself," it would be helpful to note that String overrides equals() to provide a proper content equality check, but Array doesn't (surprise!).Biquadrate
B
14

In Kotlin, two types of equality are available. These are: Structural Equality & Referential Equality.

class A {
  var foo = 1
}

var a1 = A()
var a2 = A()

Here a1 and a2 are two instances of class A.

println(a1 == a2)

It prints false because a1 and a2 are not structurally equal.

println(a1 === a2)

It prints false because a1 and a2 are not referencing the same object.

But, if you execute this line: a1 = a2 then,

a1 and a2 will be structurally equal and a1 is referencing to the a2 instance. That's why,

println(a1 == a2)
println(a1 === a2)

both these lines returns true.

Bobbybobbye answered 14/7, 2018 at 15:13 Comment(2)
Why are a1 and a2 not structurally equal?Sentinel
This answer is incomplete. It presents two cases in which the two operators return identical values. It would be more interesting to show a case where they differ.Decury
P
3

Structural Equality means content should be same

"checks for equals() or ==".

Referential Equality means both instances should be pointed to same pointer.

"two objects points to same reference or ==="

You can override equals() and do the stuff as below.

class Person(val p : String) {

  override fun toString(): String = "Person(p$p)"
    override fun equals(other: Any?): Boolean {
        if(other == null || other !is Person) {
           return false
        }
       return p == other.p
    }
}

lets test this.

var a = Person("abc")
var b = Person("abc")

Line 1 => println(a == b)
Line 2 => println(a === b)

Line1 prints "true"

Line2 prints "false"

a = b

Line1 prints "true"

Line2 prints "true"

Finally,

=== always checks for reference equality while == checks for equivalent content and is based on your implementation.

Physiological answered 24/8, 2022 at 6:38 Comment(0)
U
1

Kotlin == and === operators (fresh look : 6 cases)

In Kotlin if a and b represent two variables then println(a==b) checks whether the two values are structurally equal or not. But println(a===b) checks whether a and b are having the same reference or not. Following examples would make this clear.

// Case 1 : a and b are both Int
// EqCase1.kt
fun main() {
    var a = 5
    var b = 7
    println(a==b) // false
    //println(a===b) // identity equality for Int is deprecated
    a = b
    println(a==b) // true
    //println(a===b) // identity equality for Int is deprecated
}


// Case 2 : a and b are Double and Integer
// EqCase2.kt
fun main() {
    var a = 5.0
    var b = 7
    //println(a==b) //  operator '==' cannot be applied to 'Double' and 'Int'
    //println(a===b) // operator '===' cannot be applied to 'Double' and 'Int'
    //a = b // inferred type is Int but Double was expected
    //println(a==b) //  inferred type is Int but Double was expected
    println(a===b) // identity equality for Int is deprecated
}


// case 3 : a and b are mathematically same but of different types (Double and Any(say Int))
// EqCase3.kt
fun Eq(a: Double,b: Any) =  if (a == b) "(a == b) is true" else "(a == b) is false"
//fun Eq1(a: Double,b: Any) =  if (a === b) "(a === b) is true" else "(a === b) is false"
fun main() {
    println(Eq(5.0,5)) // (a == b) is false
    //println(Eq1(5.0,5)) 
}

/* O/p
EqCase3.kt:5:34: warning: identity equality for arguments of types Double and Any can be unstable because of implicit boxing
fun Eq1(a: Double,b: Any) =  if (a === b) "(a === b) is true" else "(a === b) is false"
*/


// Case 4 : a and b are both Booleans
// EqCase4.kt
fun main() {
    var a = true
    var b = false
    println(a==b) // false
    //println(a===b) // identity equality for arguments of Boolean is deprecated
    a = b
    println(a==b) // true
    //println(a===b) // identity equality for arguments of Boolean is deprecated
}


// Case 5 : a and b are both Strings
// EqCase5.kt
fun main() {
    var a = "Anil"
    var b = "Vijay"
    println(a==b) // false
    println(a===b) // false
    a = b
    println(a==b) // true
    println(a===b) // true
}


// Case 6 : a and b are both of type arrayOf
// EqCase6.kt
fun main() {
    var a = arrayOf("A","B","C")
    var b = arrayOf("a","b","c")
    println(a==b) // false
    println(a===b) // false
    a = b
    println(a==b) // true
    println(a===b)  // true
}
Uncounted answered 19/12, 2022 at 18:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.