0

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?

3 Answers 3

2
  1. == calls the Object's equals(Any?) method, not your overload. So you need to have override operator fun equals(other: Any?) everywhere.

  2. 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 } 
Sign up to request clarification or add additional context in comments.

2 Comments

side question.. is there a reason to prefer the when expression over just other is Foo && other.value == value ? (I was surprised this actually works; I keep forgetting the "once you test it, we can make assumptions about it bit that the compiler is willing to do as side effects)
No, I like that version better, I just didn't think about it.
2

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 } } 

Comments

1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.