Tamir Abutbul
Tamir Abutbul

Reputation: 7661

What is the difference between compareTo and equals in Kotlin?

I want to fully understand the different between compareTo and equals.

I have used this code while trying to understand the difference between them:

println("${'A'.compareTo('b')}")
println("${'A'.equals('b')}")

While using compareTo I get -1 as a result. Nothing is wrong here. It is also mentioned in the documentation that I will get -1 as a result if the strings are not the same:

Compares this object with the specified object for order. Returns zero if this object is equal to the specified other object, a negative number if it's less than other, or a positive number if it's greater than other.

And while using equals the result that I got was false, then again it looks good as the documentation mentioned - this method will return a boolean:

Indicates whether some other object is "equal to" this one.

Maybe I am missing something really simple, but in the described case, what is the difference between those methods (other than the value that is coming from compareTo and equals)?

Upvotes: 0

Views: 5463

Answers (2)

LuCio
LuCio

Reputation: 5193

It is basically the same as in Java. The Kotlin documentation is rather short. The Java documentation is more precise and worth to be taken into account. The "API Note" is especially important:

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)).

This means there are exceptions like:

  println(BigDecimal("1.0").compareTo(BigDecimal.ONE)) // 0 -> no difference
  println(BigDecimal("1.0").equals(BigDecimal.ONE)) // false -> different

While it is a compile time error in Java it is valid in Kotlin to write:

  println(1.compareTo(1)) // 0

But there is a more significant difference. Kotlin allows to provide custom implementations for operators. Its called operator overloading.

Let's look at an example:

class Speed(val value: Int, val unit: SpeedUnit) : Comparable<Speed> {
  override fun compareTo(other: Speed): Int {...}
  override fun equals(other: Any?): Boolean {{...}
}

enum class SpeedUnit {
  KMH, MPH
}

While it is valid in Java and Kotlin to write

Speed(10, Unit.KMH).compareTo(Speed(10, Unit.MPH))

it is only valid in Kotlin to write

Speed(10, Unit.KMH) < (Speed(10, Unit.MPH))

The operators < > <= >= are shorthands of the compareTo method.

It is valid for both Java and Kotlin to write

Speed(10, Unit.KMH) == (Speed(10, Unit.MPH))

But as for Java this will always return false since == compares the object identity. In Kotlin == is the operator corresponding to equals.

Upvotes: 0

Benjamin Charais
Benjamin Charais

Reputation: 1368

The difference between equals and compareTo comes from a few sources.

First, equals is inherited from the Any type in Kotlin, so it is a method attached to all values in the language.

compareTo is inherited from the Comparable type, specifically meaning only its inheritors of:
Boolean, Byte, Char, Double, Duration, Enum, Float, Int etc... will have the method.


Second, the signature of returned value is different. Equals has a return of Boolean, meaning you only have true or false being returned from the method call. This will only tell you directly if they are the same or not, with no extra information

The compareTo method has a return of Int, which is a magnitude of the difference between the comparison of the input type. The comparison can not be between different types.

The return of a positive Integer that the Receiver value, is greater than the input value being checked against To clarify, the Receiver is the variable or instance that the compareTo method is being called on. For example:

val myValue: Boolean = false
val myCheck: Boolean = true

myValue.compareTo(myCheck) // Return: 1

In that code, the Receiver would be myValue because it is calling the method compareTo. Kotlin interprets true to be a greater value than false so myValue.compareTo(myCheck) will return1`

The return of 0 means that the Receiver value is the same value as the input parameter value.

val myValue: Boolean = true
val otherValue: Boolean = true
myValue.compareTo(otherValue) // Return: 0

The return of a negative number is a magnitude of difference between the two values, specific to each type based on the Receiver value being considered a value of less than the input parameter.

val myString = "zza"
val otherString = "zzz"

myString.compareTo(otherString) // Return: -25

The equality being a bit complicated to explain, but being the same length with only 1 Char place being different, it returns the difference of the Char values as an Int.

val myString = "zz"
val otherString = "zzz"

myString.compareTo(otherString) // Return: -1

In this case the difference is literally the existence of 1 Char, and does not have a value difference to assign.


For equals, the comparative other can be of Any type, not specifically the same type as the Receiver like in compareTo. The equals method is also an operator function and can be syntactically used such as:

val myString: String = "Hello World"
val otherString: String = "Hello World"

myString == otherString // Return: true

Any non-null value can not be equal to null:

val myString = "Hello World"
val maybeNull: String? = null

myString == maybeNull // Return: false

Equality is specific to each type and has it's own specific documentation to clarify its nuances: Kotlin Equality

Upvotes: 2

Related Questions