Question regarding custom equality of sealed class...
# getting-started
t
Question regarding custom equality of sealed class children:
Regarding the problem in this thread, I thought one could write
Copy code
fun main() {
    println(Status.Good.equals(Status(1))) // 1

    println(Status.Good == Status.Good)    // 2
    println(Status.Good == Status(1))      // 3
    println(Status(1) == Status(1))        // 4

    println(Status.Good == Status.Bad)     // 5
    println(Status.Good == Status(2))      // 6
    println(Status(1) == Status(2))        // 7
}

sealed class Status(open val code: Int, val name: String?) {
    override fun equals(other: Any?) = (other as? Status)?.code == code

    object Good : Status(1, "Good")
    object Bad : Status(2, "Bad")
    object Ugly : Status(2, "Ugly")
    data class Arbitrary(override val code: Int) : Status(code, null)

    companion object {
        operator fun invoke(code: Int) = Arbitrary(code)
    }
}
But comparisons 3, 5 and 6 fail to compile: "Operator '==' cannot be applied to ..." However, comparison 1 passes, and "Go To: Declaration" on the equal signs take me to the same
override fun equals(...)
of the sealed class. I thought that
a == b
is just a shortcut for
a.equals(b)
. Am I wrong?
c
I'm surprised this doesn't compile… the documentation doesn't mention anything like this
m
Is it a compile error or a warning with all warns error flag enabled? This seems like it should be legal, but I could see the compiler trying to warn you that you might be doing something wrong. Normally equality comparisons between different types will always be false, and this can tell they are different types at compile time.
c
It is a compilation error.
It's possible to force the compiler to accept it, but it's not great.
w
It might be just Kotlin trying to prevent you from making comparisons that generally don't make sense. Kotlin's type system can't prevent you from accidentally comparing two different types that have no common subtypes. But other languages (such as Swift) have made this impossible using their type system (through
Self
types). I don't know in which use case this makes sense. But in the rare use case that you would ever need such comparison, I think it's not that far fetched to use
.equals
m
The documentation is lacking on mentioning anything about what types can be compared using
==
. Just that
== null
is handled.
r
Also interesting, if you just specify the return type of
invoke
like so:
Copy code
operator fun invoke(code: Int): Status = Arbitrary(code)
3 and 6 will now compile, but not 5
> Kotlin checks the applicability of value equality operators at compile-time and may reject certain combinations of types for
A
and
B
. Specifically, it uses the following basic principle.
>
> If type of
A
and type of
B
are definitely distinct and not related by subtyping,
A == B
is an invalid expression and should result in a compile-time error.
>
> Informally: this principle means “no two objects unrelated by subtyping can ever be considered equal by `==`”.
🔥 1
K 1
that doesn't apply to the
.equals()
function, only the
==
operator
t
Interesting, thank you very much!