- Equality in Kotlin
- 3 Answers 3
- Referential Equality
- Structural Equality
- Equality in Kotlin (‘==’, ‘===’ and ‘equals’)
- Structural Equality (‘==’)
- Referential equality (‘===’)
- .equals method
- And what does disagree with IEEE 754 Standard for Floating-Point Arithmetic mean?
- Confused?
- Wait, but you said == and .equals only compares the contents of the object which were equal in our case.
- Few things to keep in mind,
- Kotlin — Compare values between common fields of two classes
- 3 Answers 3
Equality in Kotlin
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)
3 Answers 3
Referential Equality
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».
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.
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.
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.
== 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) < 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 ).
Equality in Kotlin (‘==’, ‘===’ and ‘equals’)
We often need to compare the data of two variables or objects or the references of two objects in Kotlin. This brings in another question, which equality check should we use in which case. Let’s figure out what are the types of checks available in Kotlin.
Structural Equality (‘==’)
== operator is used to compare the data of two variables. Please don’t misunderstand this equality operator with the Java == operator as both are different. == operator in Kotlin only compares the data or variables, whereas in Java or other languages == is generally used to compare the references. The negated counterpart of == in Kotlin is != which is used to compare if both the values are not equal to each other.
Referential equality (‘===’)
=== operator is used to compare the reference of two variable or object. It will only be true if both the objects or variables pointing to the same object. The negated counterpart of === in Kotlin is !== which is used to compare if both the values are not equal to each other. For values which are represented as primitive types at runtime (for example, Int), the === equality check is equivalent to the == check.
.equals method
equals(other: Any?) method is implemented in Any class and can be overridden in any extending class. .equals method also compares the content of the variables or objects just like == operator but it behaves differently in case of Float and Double comparison. The difference between == and .equals is in case of Float and Double comparison, .equals disagrees with the IEEE 754 Standard for Floating-Point Arithmetic.
And what does disagree with IEEE 754 Standard for Floating-Point Arithmetic mean?
- NaN is considered equal to itself
- NaN is considered greater than any other element including POSITIVE_INFINITY
- -0.0 is considered less than 0.0
Confused?
Will explain this and everything with examples. First, let’s compare two primitive type Int variables by all the equal checks.
val int1 = 10
val int2 = 10
println(int1 == int2) // true
println(int1.equals(int2)) // true
println(int1 === int2) // true
All the above comparisions will print true because primitive datatype only checks the value in case of === also which will be equal in our case. Now let’s use the wrapper class instead of Primitive datatype and compare all three equal checks
val first = Integer(10)
val second = Integer(10)
println(first == second) //true
println(first.equals(second)) //true
println(first === second) //false
In the above case, the == and .equals prints true because they compare only values whereas === compares the references of the objects which were different so it prints false . Now, let’s consider another case where we created our own custom class object and compared with all three checks.
class Employee (val name: String)
val emp1 = Employee(“Suneet”)
val emp2 = Employee(“Suneet”)
println(emp1 == emp2) //false
println(emp1.equals(emp2)) //false
println(emp1 === emp2) //false
println(emp1.name == emp2.name) //true
println(emp1.name.equals(emp2.name)) //true
println(emp1.name === emp2.name) //true
The reason for the above comparison is obvious, As Empoyee is not a primitive datatype or wrapper class, all three compared the references, which returns false for all three checks. But in the case of string comparison, if only checks the contents of the string which were equal so it returns true for every case.
Wait, but you said == and .equals only compares the contents of the object which were equal in our case.
Exactly. But the content comparison only works if its a data class. If it’s a normal class the compiler consider both the objects as the different objects even if the content is same but if its a data class, the compiler compares the data and return true if the content is same. Let’s change the above class to data class.
data class Employee (val name: String)
val emp1 = Employee("Suneet")
val emp2 = Employee("Suneet")
println(emp1 == emp2) //true
println(emp1.equals(emp2)) //true
println(emp1 === emp2) //false
println(emp1.name == emp2.name) //true
println(emp1.name.equals(emp2.name)) //true
println(emp1.name === emp2.name) //true
val negZero = -0.0f
val posZero = 0.0f
println(negZero == posZero) //true
println(negZero.equals(posZero)) //false
println(negZero === posZero) //true
As in the case of Float and Double comparison, .equals disagrees with the IEEE 754 Standard for Floating-Point Arithmetic, it returns a false when -0.0 was compared with 0.0 whereas == and === returns true .
Few things to keep in mind,
- As there is no constructor as String(“”) in Kotlin, all string comparison will give true if the content will be equal.
- There’s no point in optimizing code when comparing to null explicitly. a == null will be automatically translated to a === null as null is a reference and at the end, it will a reference check.
Kotlin — Compare values between common fields of two classes
I need to do this: compare update to result, keep only the fields in update that are different from result and not null. How can I achieve that ? I’d appreciate any guidance.
What about fields in UserDetailsInput which do not exist in UserDetailsDTO, should they also be returned?
keep only the fields in update that are different from result and not null. What about those which are not different? They should become null? Also you are using non-nullable types in UserDetailsDTO, so they will never be null.
@lukas.j there are no such fields in the current implementation (because one of them is the output of the fields in the database, the other one is the input to change some of those fields) , but if they were they should be returned yes.
@ArpitShukla They are all nullable. I have written it here wrong. Those whose values are the same should be skipped. Example: Input username is different from result username, keep that in the final variable. Input lastName is the same from result lastName, skip that. input category is null, skip that.
3 Answers 3
You can create an utility method witch take them both and return a UserDetailsDTO with only the diff
(I never did kotlin but i think it’s something like that )
Class TestDTO() < public String name; public Int age; >Class TestInput() < public String name; public Int age; >fun TestDiff(testDTO: TestDTO,testInput : TestInput ) < finalDTO = new TestDTO(); if(testInput.name != null && testInput.name != testDTO.name)< finalDTO.name = testInput.name; >if(testInput.age != null && testInput.age != testDTO.age) < finalDTO.age = testInput.age; >return finalDTO; >
You can create an extention function like this:
fun UserDetailsInput.uniqueValue(UserDetailsDTO: UserDetailsInput)
Thank you! Would I have to check for every input field or is there a generic way to check for all ? Because there are 9-10 fields, I only added two in the example above to abstract the problem
Not very elegant. Uses reflection to check which field of UserDetailsInput exists also in the target class UserDetailsDTO:
import java.util.* import kotlin.reflect.full.memberProperties data class UserDetailsDTO( val username: String?, val id: UUID, val lastName: String? ) data class UserDetailsInput( val username: String?, val id: UUID, val lastName: String?, val firstName: String? ) val result = UserDetailsDTO("User 1", UUID.randomUUID(), "Abc") val input = UserDetailsInput("User 1", result.id, null, "Super") val mapOfDifferenValues = mutableMapOf() val propsInResult = UserDetailsDTO::class.memberProperties val propsInInput = UserDetailsInput::class.memberProperties for (propInInput in propsInInput) < // Value from Input val valueFromInput = propInInput.get(input) // Check if it is not null if (valueFromInput != null) < // Check if a field with same name exists in 'result' class if (propInInput.name in propsInResult.map < it.name >) < // A field with same name exists in result class, so check if it has the same value if (valueFromInput != propsInResult.first < it.name == propInInput.name >.get(result)) < // It does not have the same value, so add it to the map mapOfDifferenValues[propInInput.name] = valueFromInput >> else < // There is no field with the same name in 'result' class, so add it to the map mapOfDifferenValues[propInInput.name] = valueFromInput >> > println(mapOfDifferenValues)