Pairs and type inference

I always felt like this restriction on types used with equality operator is kind of hacky. Java/JVM allows us to make objects of different types to be equal. Kotlin does not complain if we try to compare supertype with its subtype. But wait, what about this code:

open class Base { ... }
class Subtype1 : Base() { ... }
class Subtype2 : Base() { ... }

val base = Base()
val subtype1 = Subtype1()
val subtype2 = Subtype2()

println(base == subtype1) // true
println(base == subtype2) // true
println(subtype1 == subtype2) // compile error

If base equals subtype1 and base also equals subtype2 then wouldn’t it make sense to assume subtype1 should equal subtype2? But such check isn’t even allowed, because it is assumed to never be true.

Also, == works differently regarding type inference than anything else in the language. Normally, the compiler tries to automatically cast objects to their supertypes to make the code compile. Note that we can safely cast Pair<Foo, Bar> to Pair<Any, Any> and now equality operator works just fine, Usually, compiler does this for us. See this example:

fun <T> checkEquality(obj1: T, obj2: T)

This function can be invoked as checkEquality(Foo(), Bar()), because then both objects are automatically cast to Any. Equality operator does not do this. It seems to have its own logic for comparing provided types. Maybe it was hardcoded to verify first level of parameter types, but it ignores deeper types?

And regarding filterIsInstance() - I consider this function not really type safe. It checks raw type only and at all ignores parameter types. It actually can’t do better for technical reasons, but this is why I think it should be disallowed to use it with parameterized types. I described this problem here: https://discuss.kotlinlang.org/t/is-as-operators-are-unsafe-for-reified-types

1 Like