views:

208

answers:

4
val filesHere = (new java.io.File(".")).listFiles
val filesHere2 = (new java.io.File(".")).listFiles

scala> filesHere == filesHere2
res0: Boolean = false

That is quite counter intuitive. I would rather expect that filesHere and filesHere2 are equal.

This is certainly due to a semantics mismatch between Java and Scala, e.g., about arrays or (files) equality. Clearly, I am missing something here!

+7  A: 

The equals() method of Java arrays uses reference equality rather than anything more sophisticated, and Scala's == is simply Java's equals().

pelotom
In Scala == and equals() are for value equality, and eq is for whether two objects have reference equality.
James Black
@James yes, but in this instance equals() is implemented to simply check reference equality. So in this particular case, (Scala's ==) == (Java's ==) :)
pelotom
Here is an interesting thread: http://scala-programming-language.1934581.n4.nabble.com/scala-Array-equality-td2001726.html But still, I am really confused. If Scala == (or "equals") actually calls the equals() method of Java (as it seems the case), this example breaks somewhat the design choice of the Scala language about equality. As a Scala programmer, I have to remind the semantics of equality in Java and be careful with all the tricky points. Damn!
acherm
You're not alone in being confused by this... it's tripped up many a hapless Scala newcomer. Do you at least understand what's going on?
pelotom
As an aside, lots of Java people say "Unless dealing with a legacy API that forces your hand, don't use arrays, use collections." Collections have strong "equals()" semantics.
Thomas Dufour
+2  A: 

You may want to read through here:

http://programming-scala.labs.oreilly.com/ch06.html#EqualityOfObjects

but it appears that if you did: filesHere.sameElements(filesHere2) that it should be true.

The javadoc for this is here: http://www.scala-lang.org/api/2.6.0/scala/IterableProxy.html#sameElements%28Iterable%5BB%5D%29

UPDATE:

A couple of snippets from the first link that may be helpful:

In Java, C++, and C# the == operator tests for reference, not value equality. In contrast, Ruby’s == operator tests for value equality. Whatever language you’re used to, make sure to remember that in Scala, == is testing for value equality.

In reference to == not working as expected on Lists:

While this may seem like an inconsistency, encouraging an explicit test of the equality of two mutable data structures is a conservative approach on the part of the language designers. In the long run, it should save you from unexpected results in your conditionals.

James Black
Nice resource, thank you! It shows how to deal with the problem mentioned above (using sameElements, OK!) but it does not explain why the problem (or the "surprise") occurs like inscala> Array(1, 2) == Array(1, 2)res0: Boolean = false
acherm
@acherm - That is why I put in the update, the last quote from the article should explain the why, to encourage explicit testing for equality.
James Black
Another interesting discussion here: http://scalide.blogspot.com/2009/05/hashcode-equals-in-scala-28-collections.html That does not fully clarify the situation, but illustrates that "equality is an interesting topic, merely because of the incredible range of interpretations there are of it." Looking at Array.scala (http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_0_final/src//library/scala/Array.scala), the equals() method is not defined.
acherm
This is not quite right about C# as == can be and often is overridden for reference types to mean value equality. Object.ReferenceEquals always means reference equality.
dpp
@dpp - When you override operators then any assumptions can be pitched. If I can make '+' do a subtraction that doesn't mean that any assumptions on the plus operator are wrong.
James Black
@James Black - You're right, of course, about the fact that operator overloading done badly (which is probably most of the time) can cause nothing but trouble. My point was that even in the BCL there are many places where == is overridden to "do the right thing" and, in my opinion, has more in common with Scala than Java in this aspect.
dpp
+5  A: 

If I ruled the world, I would deprecate Scala's eq method on the grounds that the name is extremely confusible with equals and ==. Instead English does have a word which expresses identity as opposed to equality: I would simply call it is .

Similarly I would replace Scala's ne (which is a terrible name, since it's both an abbreviation and incomprehensible) with isnt .

Seems to me these could actually be added to AnyRef and the old methods deprecated, even at this late stage.

Jonathan
I like that idea a lot.
Ian McLaird
+7  A: 

The comparison doesn't work as expected, because this Java API returns an Array.

Scala's arrays and Java arrays are the same behind the scenes and although Scala's array looks like a class it is just a java.io.File[] (in this example).

This is the reason why the check for equality can't be overridden. Scala has to use Java semantics for it.

Consider this example:

val filesHere = (new java.io.File(".")).listFiles.toList
val filesHere2 = (new java.io.File(".")).listFiles.toList

This would work as expected.

soc