Equality in Kotlin
Asked Answered
H

3

33

I'm learning Kotlin, with a C++ and Java background. I was expecting the following to print true, not false. I know that == maps to equals. Does the default implementation of equals not compare each member, i.e. firstName and lastName? If so, wouldn't it see the string values as equal (since == maps to equals again)? Apparently there's something related to equality versus identity that I haven't got right in Kotlin yet.

class MyPerson(val firstName: String, val lastName: String)

fun main(args: Array<String>) {
   println(MyPerson("Charlie", "Parker") == MyPerson("Charlie", "Parker"))
}
Hangeron answered 19/8, 2017 at 14:54 Comment(0)
M
25

The default equals implementation you're describing exists only for data classes. Not for regular classes where the implementation is inherited from Any, and just make the object equal to itself.

Molly answered 19/8, 2017 at 15:15 Comment(2)
So, if equals is not overridden for a regular class, it's essentially the same as calling ===.Tempo
@Tempo Exactly the answer I'm looking for.Differentia
A
61

Referential Equality

Java

In Java, the default implementation of equals compares the variable's reference, which is what == always does:

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

We call this "referential equality".

Kotlin

In Kotlin == is compiled to equals, whereas === is the equivalent of Java's ==.

Structural Equality

Whenever we want rather structural than referential equality, we can override equals, which is never done by default for normal classes, as you suggested. In Kotlin, we can use data class, for which the compiler automatically creates an implementation based on the constructor properties (read here).

Please remember to always override hashCode if you override equals (and vice versa) manually and stick to the very strict contracts of both methods. Kotlin's compiler-generated implementations do satisfy the contract.

Antagonism answered 19/8, 2017 at 18:29 Comment(1)
In kotlin you can ctrl + click the == operator and you will see that is the same as equals as this answer tells, if you ctrl + click on the equals method you will also see that links to the same implementation.Inscription
M
25

The default equals implementation you're describing exists only for data classes. Not for regular classes where the implementation is inherited from Any, and just make the object equal to itself.

Molly answered 19/8, 2017 at 15:15 Comment(2)
So, if equals is not overridden for a regular class, it's essentially the same as calling ===.Tempo
@Tempo Exactly the answer I'm looking for.Differentia
K
17

== for equality

In Java, you can use == to compare primitive and reference types. If applied to primitive types, Java’s == compares values, whereas == on reference types compares references. Thus, in Java, there’s the well-known practice of always calling equals, and there’s the well-known problem of forgetting to do so.

In Kotlin, == is the default way to compare two objects: it compares their values by calling equals under the hood. Thus, if equals is overridden in your class, you can safely compare its instances using ==. For reference comparison, you can use the === operator, which works exactly the same as == in Java.

class MyPerson(val firstName: String, val lastName: String){
    override fun equals(other: Any?): Boolean {
        if (other == null || other !is MyPerson) return false
        return firstName == other.firstName && lastName == other.lastName
    }
}

fun main(args: Array<String>) {
    println(MyPerson("Charlie", "Parker") == MyPerson("Charlie", "Parker")) // print "true"
}

In your case MyPerson is used to be a data class which autogenerate implementations of universal methods (toString, equals, and hashCode).

Kaczmarek answered 19/8, 2017 at 21:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.