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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.