Equality testing


#1

It appears that:

listOf(0) == listOf(0)

evaluates true, but that:

arrayOf(0) == arrayOf(0)

evaluates false. This most definitely violates the Principle of Least Surprise. Personally I consider this an error, but thought I would open up discussion here before filing a bug report.


#2

AFAIK the problem is that the equals methods of array simply checks for reference equality, and == desugars to equals (with some subtlety for nulls).

Now you could special case == in case where arrays are involved

If you use the static type, which means that you will get the old, default behavior when you pass arrays as Object. Sure, that is much less common, but it would be a real puzzler when it happens.

Otherwise you need to perform a dynamic type check, which has overhead. That may be fine however (especially since you only have to do it with Object, other types can’t be arrays).


#3

@norswap It is indeed the value equality vs identity equality thing. The problem here is this unexposed inconsistency between List and Array, both are classes and yet because of how they are implemented == behaves so very differently. Similar things with the spread operator. The problem is less the operator semantics, than the inconsistency at the programmer level.


#4

I’m not sure it’s correct to say that array are classes. They just share the syntax in Kotlin. I’m not sure this was a judicious decision, seeing how array are different beasts.

The Array/List inconsistency is something inherited from the JVM, it would take a lot of beating around the bush to even approximate consistency between Array and List (another one: array don’t have an immutable view).

I think that the key principle here is compatibility with Java and that, as much as possible, things should behave as in Java. Equality behaving differently in Java and Kotlin code would be a departure from that principle in my opinion.


#5

I agree this is a difficult problem with no easy answer now. I suspect it may be too late to fix now; measures could be taken to make the distinction clearer.


#6

Afaik the JB position on that is not to use arrays when possible. But I also would like a data structure with fixed size but mutable elements, e.i with set but without add


#7

I may be missing something, but you can only use the spread operator with Array, not with List, this means using Array in some places of this code so it is better to use Array everywhere, except that you then have to worry about equals and hash.


#8

That’s the only thing you can do with arrays that you can’t with lists. Many handy stdlib functions are not implemented for arrays because that would take too many code since all specialised array functions are auto-generated not to use generics and avoid boxing


#9

It would be interesting to benchmark Array vs List performance to see if once can simply forget Array (even though this means losing spread operator, which is a fantastic tool).


#10

What’s up with the spread operator? List.toTypedArray allows to convert with a simple copying. How often do you use vararg and the spread operator anyway?


#11

Coming from a Groovy background, I use the spread operator a lot manipulating lists. I guess I could flatMap everything but that seems excessive.


#12

I hope this helps you.


#13

By the way spread operator for collections is being considered in https://youtrack.jetbrains.com/issue/KT-12663.


#14

Thanks for letting us know. I have voted for this, it makes so much sense for at least lists as well as arrays.