44

What is the difference between methods ## and hashCode?

They seem to be outputting the same values no matter which class or hashCode overloading I use. Google doesn't help, either, as it cannot find symbol ##.

5
  • 1
    1.0 hashCode v 1.0 ## v 1 hashCode v 1 ##scala-lang.org/api/current/scala/Any.html Commented Jan 30, 2012 at 17:50
  • 5
    A little offtopic, but you can search for such symbols using SymbolHound. Commented Jan 30, 2012 at 18:10
  • 2
    Ah ok. So, 1.hashCode == 1.##, and 1.2.hashCode == 1.2.##. The only thing that behaves differently is 1.0.hashCode != 1.0.## (so ## is better suited for comparing numbers). Commented Jan 30, 2012 at 18:14
  • 1
    From the Scala docs on Any "Equivalent to x.hashCode except for boxed numeric types. For numerics, it returns a hash value which is consistent with value equality: if two value type instances compare as true, then ## will produce the same hash value for each of them.". Commented Jan 30, 2012 at 18:15
  • @om-nom-nom, a little of topic, but thanks for the tip. That's awesome! Commented Feb 19, 2014 at 10:36

4 Answers 4

40

"Subclasses" of AnyVal do not behave properly from a hashing perspective:

scala> 1.0.hashCode
res14: Int = 1072693248

Of course this is boxed to a call to:

scala> new java.lang.Double(1.0).hashCode
res16: Int = 1072693248

We might prefer it to be:

scala> new java.lang.Double(1.0).##
res17: Int = 1

scala> 1.0.##
res15: Int = 1

We should expect this given that the int 1 is also the double 1. Of course this issue does not arise in Java. Without it, we'd have this problem:

Set(1.0) contains 1 //compiles but is false

Luckily:

scala> Set(1.0) contains 1
res21: Boolean = true
Sign up to request clarification or add additional context in comments.

1 Comment

So, when implementing both equals and hashCode for a particular class, I'm not sure how this translates into the best strategy. I am assuming the hashCode implementation should use ##. However, should the equals implementation use hashCode or ##? Here's the answer I provided on another thread which assumes that the equals implementation should use hashCode and the hashCode implementation should use ##. Evaluation and feedback on this would be greatly appreciated. stackoverflow.com/a/56509518/501113
35

## was introduced because hashCode is not consistent with the == operator in Scala. If a == b then a.## == b.## regardless of the type of a and b (if custom hashCode implementations are correct). The same is not true for hashCode as can be seen in the examples given by other posters.

1 Comment

So, when implementing both equals and hashCode for a particular class, I'm not sure how this translates into the best strategy. I am assuming the hashCode implementation should use ##. However, should the equals implementation use hashCode or ##? Here's the answer I provided on another thread which assumes that the equals implementation should use hashCode and the hashCode implementation should use ##. Evaluation and feedback on this would be greatly appreciated. stackoverflow.com/a/56509518/501113
6

Just want to add to the answers of other posters that although the ## method strives to keep the contract between equality and hash codes, it is apparently not good enough in some cases, like when you are comparing doubles and longs (scala 2.10.2):

> import java.lang._
import java.lang._

> val lng = Integer.MAX_VALUE.toLong + 1
lng: Long = 2147483648

> val dbl = Integer.MAX_VALUE.toDouble + 1
dbl: Double = 2.147483648E9

> lng == dbl
res65: Boolean = true

> lng.## == dbl.##
res66: Boolean = false

> (lng.##, lng.hashCode)
res67: (Int, Int) = (-2147483647,-2147483648)

> (dbl.##, dbl.hashCode)
res68: (Int, Int) = (-2147483648,1105199104)

3 Comments

Really? Is this a bug?
It clearly is as according to scaladoc for ## "... it returns a hash value which is consistent with value equality: if two value type instances compare as true, then ## will produce the same hash value for each of them..."
I just checked this in scala 2.11.7 and did not see the same behavior for == and .## == .##
3

In addition to what everyone else said, I'd like to say that ## is null-safe, because null.## returns 0 whereas null.hashCode throws NullPointerException.

From scaladoc:

Equivalent to x.hashCode except for boxed numeric types and null. For numerics, it returns a hash value which is consistent with value equality: if two value type instances compare as true, then ## will produce the same hash value for each of them. For null returns a hashcode where null.hashCode throws a NullPointerException.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.