Scala Programming Language
  1. Scala Programming Language
  2. SI-5640

Scala hash code of some Double objects is different when it is seen as Double and when it is seen as Any

    Details

      Description

      The same object d below has different scala hash code
      when it is seen as static type Double and when it is seen as static type Any .

      def testHashHash {
        val d = (BigInt(1) << 64).toDouble
        val a: Any = d
        println("d.hashCode="+d.hashCode)
        println("d.##="+d.##)
        println("a.##="+a.##)
        assert(d.## == a.##)
      }
      

      This is because BoxesRunTime.hashFromDouble(java.lang.Double n) and ScalaRunTime.hash(dv: Double) don't match.

        Activity

        Hide
        Miguel Garcia added a comment -

        Minimized further:

        scala> val d = (BigInt(1) << 64).toDouble
        d: Double = 1.8446744073709552E19
        
        scala> val a: Any = d
        a: Any = 1.8446744073709552E19
        
        scala> scala.Double.box(d).hashCode()
        res0: Int = 1139802112
        
        scala> scala.runtime.ScalaRunTime.hash(d)
        res1: Int = 1602224128
        
        scala> scala.runtime.ScalaRunTime.hash(a)
        res2: Int = 1139802112
        
        Show
        Miguel Garcia added a comment - Minimized further: scala> val d = (BigInt(1) << 64).toDouble d: Double = 1.8446744073709552E19 scala> val a: Any = d a: Any = 1.8446744073709552E19 scala> scala.Double.box(d).hashCode() res0: Int = 1139802112 scala> scala.runtime.ScalaRunTime.hash(d) res1: Int = 1602224128 scala> scala.runtime.ScalaRunTime.hash(a) res2: Int = 1139802112
        Hide
        Dominik Gruntz added a comment -

        Actually, a and d have the same hashCode. It is ## which returns different results than hashCode for boxed numeric types (and for null) as documented.

        scala> val d = (BigInt(1) << 64).toDouble
        d: Double = 1.8446744073709552E19
        
        scala> val a: Any = d
        a: Any = 1.8446744073709552E19
        
        scala> d.hashCode
        res22: Int = 1139802112
        
        scala> a.hashCode
        res23: Int = 1139802112
        

        So if this behavior is changed, do not forget to update the docs of ## as well.

        Show
        Dominik Gruntz added a comment - Actually, a and d have the same hashCode . It is ## which returns different results than hashCode for boxed numeric types (and for null ) as documented. scala> val d = (BigInt(1) << 64).toDouble d: Double = 1.8446744073709552E19 scala> val a: Any = d a: Any = 1.8446744073709552E19 scala> d.hashCode res22: Int = 1139802112 scala> a.hashCode res23: Int = 1139802112 So if this behavior is changed, do not forget to update the docs of ## as well.
        Hide
        Paul Phillips added a comment - - edited
        ## isn't supposed to give different answers based on the static type of the argument.
        That (x: Any).## != (x: Foo).## is definitely a bug.  This is already recognized in the doc for ##.
        "if two value type instances compare as true, then ## will produce the same hash value for each of them."
        
        Show
        Paul Phillips added a comment - - edited ## isn't supposed to give different answers based on the static type of the argument. That (x: Any).## != (x: Foo).## is definitely a bug. This is already recognized in the doc for ##. "if two value type instances compare as true, then ## will produce the same hash value for each of them."
        Hide
        Paul Phillips added a comment -

        Oh yeah, I forgot how irreconcilable this situation is. What I said is only true up to about 16 bits of width, then it becomes impossible.

        Show
        Paul Phillips added a comment - Oh yeah, I forgot how irreconcilable this situation is. What I said is only true up to about 16 bits of width, then it becomes impossible.
        Hide
        Paul Phillips added a comment -

        58bb2d1bd2

        Show
        Paul Phillips added a comment - 58bb2d1bd2
        Hide
        Dominik Gruntz added a comment -

        runtime.BoxesRunTime.hashFromDouble(d) still returns the wrong value. Should that also be fixed, or is this method no longer used anywhere (in the context of ##)?
        I claim that hashFromDouble should also check whether the argument can be represented correctly within a float and then return that hashCode.

        scala> runtime.BoxesRunTime.hashFromNumber(d)
        res16: Int = 1139802112
        
        scala> runtime.BoxesRunTime.hashFromNumber(d.toFloat)
        res17: Int = 1602224128
        
        scala> d == d.toFloat
        res18: Boolean = true
        
        Show
        Dominik Gruntz added a comment - runtime.BoxesRunTime.hashFromDouble(d) still returns the wrong value. Should that also be fixed, or is this method no longer used anywhere (in the context of ## )? I claim that hashFromDouble should also check whether the argument can be represented correctly within a float and then return that hashCode. scala> runtime.BoxesRunTime.hashFromNumber(d) res16: Int = 1139802112 scala> runtime.BoxesRunTime.hashFromNumber(d.toFloat) res17: Int = 1602224128 scala> d == d.toFloat res18: Boolean = true
        Hide
        Paul Phillips added a comment -

        Sorry, I'm doing things in a bit of a rush. I see there are redundant implementations in BoxesRunTime and ScalaRunTime, don't know why. If you are up for sending a pull request I'd be thrilled.

        Show
        Paul Phillips added a comment - Sorry, I'm doing things in a bit of a rush. I see there are redundant implementations in BoxesRunTime and ScalaRunTime, don't know why. If you are up for sending a pull request I'd be thrilled.
        Hide
        Dominik Gruntz added a comment -

        really? here it is: b5919100e7

        Show
        Dominik Gruntz added a comment - really? here it is: b5919100e7

          People

          • Assignee:
            Paul Phillips
            Reporter:
            Dmitry Nadezhin
          • Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development