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

James Black
  • 41,583
  • 10
  • 86
  • 166
acherm
  • 73
  • 1
  • 4

4 Answers4

17

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
  • 181
  • 2
  • 3
    Yeah, good idea, but "is" is ambiguous with type checks like: obj is String, which is popular in other languages, and thus confusing. – tuxSlayer Aug 04 '11 at 01:55
8

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

Tom Crockett
  • 30,818
  • 8
  • 72
  • 90
  • In Scala == and equals() are for value equality, and eq is for whether two objects have reference equality. – James Black Aug 06 '10 at 10:02
  • 1
    @James yes, but in this instance equals() is implemented to simply check reference equality. So in this particular case, (Scala's ==) == (Java's ==) :) – Tom Crockett Aug 06 '10 at 10:10
  • 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 Aug 06 '10 at 10:22
  • 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? – Tom Crockett Aug 06 '10 at 10:41
  • 1
    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 Aug 06 '10 at 12:58
8

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
  • 27,983
  • 20
  • 111
  • 215
  • @FUD yeah, because it's an Array. But if you call `.toList` -- it will start to work. This is because it will become a class from the Scala world, and classes in Scala are defined with a nicer `equals`. – VasiliNovikov Sep 02 '14 at 08:47
4

You may want to read through here:

http://ofps.oreilly.com/titles/9780596155957/AdvancedObjectOrientedProgramming.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.

UPDATE 2:

Based on comments from Raphael I looked at the specification, and it was dated two days ago for the most recent update, and I see these at http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf:

Method equals: (Any)Boolean is structural equality, where two instances
are equal if they both belong to the case class in question and they have equal
(with respect to equals) constructor arguments.

class AnyRef extends Any {
    def equals(that: Any): Boolean = this eq that
    final def eq(that: AnyRef): Boolean = . . . // reference equality

So, it appears that the definition hasn't changed in Scala 2.10.2, as the specification seems to be consistent. If the behavior is different, then if you write a unit test it should be sent as a bug for Scala.

James Black
  • 41,583
  • 10
  • 86
  • 166
  • 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 in scala> Array(1, 2) == Array(1, 2) res0: Boolean = false – acherm Aug 06 '10 at 10:32
  • @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 Aug 06 '10 at 10:35
  • 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 Aug 06 '10 at 11:05
  • 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. – denis phillips Aug 08 '10 at 01:27
  • @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 Aug 08 '10 at 01:30
  • @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. – denis phillips Aug 08 '10 at 19:42
  • Link was moved: http://ofps.oreilly.com/titles/9780596155957/AdvancedObjectOrientedProgramming.html#EqualityOfObjects – Nikolaos Dec 28 '12 at 12:53
  • The semantics of `equals` and `==` seem to have changed (back to Java-style) with recent updates. Can you confirm? – Raphael Aug 15 '13 at 16:01
  • @Raphael - based on these two links it appears to not have changed: http://programmers.stackexchange.com/questions/193638/why-didnt-operator-string-value-comparison-make-it-to-java, http://blog.scala4java.com/2013/05/scala-equality-in-30-seconds.html – James Black Aug 16 '13 at 05:02
  • @JamesBlack I was looking at the [API of 2.10.2](http://www.scala-lang.org/api/current/scala/Any.html) which is more recent than the question on [programmers.SE] you link. At least, I read "equality" as "the same object" and "equivalence" as "the same value". Some mini tests I performed with a friend were confusing (overwriting `equals` seems to affect calls to both `equals` and `==`), so I thought I'd ask. Do you think I should open a proper question? (The second link does not work for me.) – Raphael Aug 16 '13 at 06:26
  • @Raphael - I just updated my answer, but according to the specification my answer is still consistent, it appears. – James Black Aug 17 '13 at 01:22
  • @JamesBlack Thanks. I still don't get how `==` fits into the picture, and how overwriting `equals` changes both even though they are different specification. Do case classes behave differently than normal classes? – Raphael Aug 17 '13 at 13:17
  • 1
    @Raphael - If you look at http://www.scala-lang.org/old/node/258 you will see that the equals function in case classes is redefined to compare structurally (the values) automatically. I don't see how equals could change both either, actually, but you may find this answer helpful: http://stackoverflow.com/a/7681243/67566 – James Black Aug 17 '13 at 13:30
  • Thanks, that helped. We seem to have missed `eq` entirely. – Raphael Aug 18 '13 at 11:16