Reputation: 22252
I'm trying to implement a class tree of related types (for example, e.g AST nodes) with a common abstract superclass. I'm trying to implement equals()
on the subnodes so that different sub types are indeed different, but two like types can do a more introspective computation of equality. I've tried this:
abstract class Something {
abstract fun equals(other:Something) : Boolean
}
class Foo(val value:Int):Something() {
override fun equals(other:Something) : Boolean {
return (other as Foo).value == value
}
}
class Bar(val value:Int):Something() {
override fun equals(other:Something) : Boolean {
return (other as Bar).value == value
}
}
fun main(args: Array<String>) {
val foo1:Something = Foo(1) // if i don't type these as the abstract type
val foo2:Something = Foo(1) // then I it won't even let me check
val bar1:Something = Bar(42) // if bar1 == foo1, because they're inferred
val bar2:Something = Bar(42) // as different types
println("foo1 == foo2 ${foo1 == foo2}") // should print true
println("bar1 == bar2 ${bar1 == bar2}") // should print true
println("foo1 == bar1 ${foo1 == bar2}") // should print false
}
Unfortunately, all of the println
's just show false though. What am I doing wrong?wrong?
Upvotes: 0
Views: 295
Reputation: 5033
When you use syntax foo1 == foo2
Kotlin calls function:
open operator fun equals(other: Any?): Boolean
of class Any
and not your custom equals implementation.
You need to use syntax foo1.equals(foo2)
to do what you want. Also, like Alexey Romanov pointed in his answer, you cannot cast Foo
to Bar
and vice versa, you need to do:
override fun equals(other:Something) : Boolean {
return when(other) {
is Foo -> other.value == value
is Bar -> other.value == value
else false
}
}
in both Foo
and Bar
classes.
Upvotes: 1
Reputation: 17248
If you want ==
to work properly, You have to override operator fun equals(other: Any?) : Boolean
.
If you want to explicitly require implementation in subclasses so you don't forget about it, you can mark it as abstract
in the superclass:
abstract class Something {
abstract override operator fun equals(other: Any?) : Boolean
}
class Foo(val value:Int):Something() {
override fun equals(other: Any?): Boolean {
return (other as Foo).value == value
}
}
class Bar(val value:Int):Something() {
override fun equals(other: Any?): Boolean {
return (other as Bar).value == value
}
}
Upvotes: 2
Reputation: 170723
==
calls the Object
's equals(Any?)
method, not your overload. So you need to have override operator fun equals(other: Any?)
everywhere.
Your implementations will throw exception instead of returning false
for wrong types, that's bad. Instead you need
// in Foo
override fun equals(other: Any?) : Boolean = when (other) {
is Foo -> other.value == value
else -> false
}
Upvotes: 2