I'm not certain of the reason for this error, but it might be related to a deeper problem with your approach…

In Kotlin (and Java), the equals() method has a fairly tight specification.  One condition is that it must be symmetric: whenever a and b are not null, a.equals(b) must always give the same result as b.equals(a).

But your implementation fails this test, because CS("abc").equals("abc") returns true, while "abc".equals(CS("ABC")) is false.  That's because your class knows about CharSequences such as String, but String does not know about your class.

There's no easy way around that.  In general, it's much safer to allow instances of a class to equal only instances of that class.  If you control both classes, then there are ways around that, but they're quite subtle and involved.  (Perhaps the best explanation is by Martin Odersky et al.)

So most implementations of equals() tend to work along these lines:

override fun equals(other: Any?)
    = (other is ThisClass)
    && field1 == other.field1
    && field2 == other.field2
    // ...

As I said, I don't know why the Kotlin compiler is complaining in your case.  It may be that it has spotted something of this problem, or it may be something unrelated.  But I don't think you're going to be able to fix your program in a way that equality checks will do what you want, so perhaps it's best to take this as a hint to try a slightly different approach!

Answer from gidds on Stack Overflow
Top answer
1 of 3
37

I'm not certain of the reason for this error, but it might be related to a deeper problem with your approach…

In Kotlin (and Java), the equals() method has a fairly tight specification.  One condition is that it must be symmetric: whenever a and b are not null, a.equals(b) must always give the same result as b.equals(a).

But your implementation fails this test, because CS("abc").equals("abc") returns true, while "abc".equals(CS("ABC")) is false.  That's because your class knows about CharSequences such as String, but String does not know about your class.

There's no easy way around that.  In general, it's much safer to allow instances of a class to equal only instances of that class.  If you control both classes, then there are ways around that, but they're quite subtle and involved.  (Perhaps the best explanation is by Martin Odersky et al.)

So most implementations of equals() tend to work along these lines:

override fun equals(other: Any?)
    = (other is ThisClass)
    && field1 == other.field1
    && field2 == other.field2
    // ...

As I said, I don't know why the Kotlin compiler is complaining in your case.  It may be that it has spotted something of this problem, or it may be something unrelated.  But I don't think you're going to be able to fix your program in a way that equality checks will do what you want, so perhaps it's best to take this as a hint to try a slightly different approach!

2 of 3
3

The == operator in Kotlin doesn't work if the types on both sides of the operation are known and different from each other.
For example:

3 == "Hello"
true == 5.0
// and so on

Will give a compile error because the compiler infers that operands are instances of different classes and therefore cannot be equal.

The only exception is if one side of the operator is a subclass of the other:

open class A
class B: A()
class C: A()

val c = C()
val b = B()
val a = A()

c == b
c == a // good
a == b // also good

In this case, c == b will give a compile error, while the other two operations will not.

That is why when you cast one side of the operation to Any it no longer gives an error since everything is a subtype of Any.

🌐
Kotlin
kotlinlang.org › docs › equality.html
Equality | Kotlin Documentation
By default, the equals() function implements referential equality. However, classes in Kotlin can override the equals() function to provide a custom equality logic and, in this way, implement structural equality.
🌐
Kotlin Discussions
discuss.kotlinlang.org › t › when-implementing-comparable-overriding-equals-and-hashcode-is-must › 24390
When implementing Comparable overriding equals and hashcode is must? - Kotlin Discussions
March 12, 2022 - Whenever I implement Comparable Interface then should I have to override equals() and hashcode(). Let Suppose, I have to use Priority Queue and I have custom class. So to use Priority Queue I have to implement Comparable. But my confussion is It might have two different order and it basically ...
🌐
KT Academy
kt.academy › article › ek-equals
Effective Kotlin Item 42: Respect the contract of equals
Thanks to these two alternatives, namely default and data class equality, we rarely need to implement equality ourselves in Kotlin. An example of when we might need to implement equality is when we would like to compare only one property. For instance, a User class might have an assumption that two users are equal when their id is identical. class User( val id: Int, val name: String, val surname: String ) { override fun equals(other: Any?): Boolean = other is User && other.id == id override fun hashCode(): Int = id }
🌐
Kotlin Discussions
discuss.kotlinlang.org › t › interface-overrides-equals › 8901
Interface overrides equals? - Kotlin Discussions
March 18, 2018 - I want to have a base interface A that requires all subclasses implement A have equals method that compare only the id property, which is like this: interface A{ val id:Int override fun equals(that:Any?):Boolean{//error: An interface may not implement a method of 'Any' if(that !is A) return false else return this.id == that.id } } But an error An interface may not implement a method of 'Any' appears.
🌐
Baeldung
baeldung.com › home › kotlin › equals() and hashcode() generator in kotlin
equals() and hashCode() Generator in Kotlin | Baeldung on Kotlin
May 19, 2025 - In the previous section, we looked at the default implementation of equals() and hashCode() by the compiler. If we want to provide our own implementation, we can override the equals() and hashCode() methods in our Kotlin code. For example, let’s say we want to only compare the name of the person to check for equality.
🌐
Kotlin Discussions
discuss.kotlinlang.org › support
Overloading == with different types of operands - Support - Kotlin Discussions
August 6, 2017 - Newbie here. Hopefully I’m missing something. I’m building a library for exact fractional decimal math using operator overloading. The arithmetic operators work. The fact that assignment overloading is not supported is inconvenient for the application programmer using the library, but it’s ...
Find elsewhere
🌐
DeveloperMemos
developermemos.com › posts › kotlin-overriding-equals
Kotlin Tips: Overriding equals | DeveloperMemos
Overriding the equals method is an important aspect of defining custom equality checks in Kotlin. By doing so, we can tailor object comparisons to suit specific requirements, ensuring that our code behaves as expected when performing equality checks.
🌐
Baeldung
baeldung.com › home › kotlin › kotlin classes and objects › data class’s equals() method
Data Class’s equals() Method | Baeldung on Kotlin
March 19, 2024 - If we thought p1 and p2 weren’t equal, it could lead to some problems. For example, we may use them as keys to store some data in a hashmap and expect there would be two entries. However, the latter entry will overwrite the existing one due to the fact of p1 == p2. Next, let’s understand why Kotlin tells us p1 == p2, although their dateOfBirth properties have different values.
🌐
JetBrains
youtrack.jetbrains.com › issue › KT-24874 › Support-custom-equals-and-hashCode-for-value-classes
Support custom equals and hashCode for value classes
{{ (>_<) }} This version of your browser is not supported. Try upgrading to the latest stable version. Something went seriously wrong
🌐
Medium
appmattus.medium.com › effective-kotlin-item-11-always-override-hashcode-when-you-override-equals-608a090aeaed
Effective Kotlin: Item 11 — Always override hashCode when you override equals | by Matthew Dolan | Medium
October 29, 2021 - Although there’s nothing wrong with this per se, it will return results as expected, if you already have a unique value, such as id, simply using that for the hashcode would be much more performant as it would be with equals too. ... Kotlin’s data types of Int, Long, etc.
🌐
Kotlin-quick-reference
kotlin-quick-reference.com › 104-R-object-equality.html
== and === · Kotlin Quick Reference
Comparing objects — class instances — in Kotlin is a little different than Java, and very similar to Scala. == calls equals under the hood (structural equality) ... This code shows how object equality works when a class does not have an equals method (Person) and when a class does have an equals method (PersonWithEquals): class Person(var name: String) class PersonWithEquals(var name: String) { override fun equals(that: Any?): Boolean { if (that == null) return false if (that !is PersonWithEquals) return false if (this.name == that.name) { return true } else { return false } } } fun main(a
🌐
Kotlin Discussions
discuss.kotlinlang.org › language design
How to implement `equals` and `hashCode` on `List` subtypes? - Language Design - Kotlin Discussions
May 6, 2018 - I just noticed that, in contrast to what is done in Java, the List interface in Kotlin does not define either equals or hashCode methods. This is also true for other interfaces like Set and Map. From what I understand, this means that the following statements are not necessarily true (although they actually are in practice): listOf(1) == arrayListOf(1) listOf(1).hashCode == arrayListOf(1).hashCode So, this leads to the following questions: Why doesn’t the List interface in Kotlin explicit...
Top answer
1 of 2
4

Defining equals and hashCode is considered somewhat useless on object declarations that have no explicit supertype, according to this issue. Probably correct equals+hashCode implementations on objects have few use cases.

There's even an IDE inspection that shows a warning when you try to do so:


The warning is not there when the object has a declared supertype.

However, I don't think that some technical reason stops Kotlin from resolving the overloaded operator, and the whole behaviour is strange, so I filed an issue in Kotlin issue tracker.

As for now (Kotlin 1.0.2 EAP), even with declared supertype you can only check object's equality with instances of exactly the same declared type which it has as a supertype:

object SomeObject : List<Int> by listOf() { ... }
SomeObject == listOf(1, 2, 3) // OK
SomeObject == arrayListOf(1, 2, 3) // not resolved (why?)

object MyObject : Any() { ... }
MyObject == 1 // error
MyObject == 1 as Any // OK o_O

object AnotherObject { ... }
AnotherObject == 1 as Any // works! Probably Any is supertype here

As to defining equals as an extension function: no, you can't do it because extensions are resolved statically and are shadowed by members (there's a similar question about toString).

2 of 2
2

i think your implementation is the right approach

consider this:

class MyClass {
    companion object {
         private val NUMBER: Int = 5
         private val STRING: String = "foo"

         override fun equals(other: Any?): Boolean {
                  when(other){
                     is MyClass -> {
                        return this.NUMBER == other.NUMBER &&
                               this.STRING == other.STRING
                      }
                     else -> return false
                 }
      }
}
🌐
DeepSource
deepsource.com › directory › kotlin › issues › KT-W1028
The class overrides `equals` but not `hashCode` (KT-W1028) ・ Kotlin
The class overrides the equals() method, but does not override the hashCode() method. When a class overrides the equals() method, it should also override the hashCode() method to maintain the contract between these two methods.
🌐
Kotlin
kotlinlang.org › docs › reference › equality.html
Kotlinlang
You will be redirected shortly · Redirecting… · Click here if you are not redirected
🌐
Kotlin
kotlinlang.org › docs › operator-overloading.html
Operator overloading | Kotlin Documentation
Assignments are NOT expressions in Kotlin. These operators only work with the function equals(other: Any?): Boolean, which you can override to provide a custom equality check implementation.