(Number, Number) (Float, Int), but does not match (Int, Float)

Is this a bug in Scala 2.8.0? (the same thing happens with 2.8.1.RC2)

import junit.framework._
import Assert._

class BugTest extends TestCase {

  def compare (first: Any, second: Any): Int = {
      (first, second) match {
        case (k: Int, o: Int) => k compare o
        // why the next case matches (Float, Int) but does not match (Int, Float) ???
        case (k: Number, o: Number) => k.doubleValue () compare o.doubleValue ()
        case _ => throw new Exception ("Unsupported compare" + first + ";" + second)
    }
  }

  def testCompare () {
    assertEquals ("Both Int", -1, compare (0, 1))
    assertEquals ("Both Float", 1, compare (1.0, 0.0))
    assertEquals ("Float then Int", 0, compare (10.0, 10))
    assertEquals ("Int then Float", 0, compare (10, 10.0)) // this fails with an exception
  }
}
+3
source share
2 answers

I think this is a mistake. If you look at the generated bytecode:


public int compare(java.lang.Object, java.lang.Object);
  Code:
   Stack=4, Locals=7, Args_size=3
   0:   aload_1
   1:   astore_3
   2:   aload_2
   3:   astore  4
   5:   aload_3
   6:   instanceof  #8; //class java/lang/Integer
   9:   ifeq    81
   12:  aload_3
   13:  invokestatic    #14; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
   16:  istore  5
   18:  aload   4
   20:  instanceof  #8; //class java/lang/Integer
   23:  ifeq    45
   26:  getstatic   #20; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   29:  iload   5
   31:  invokevirtual   #24; //Method scala/Predef$.intWrapper:(I)Lscala/runtime/RichInt;
   34:  aload   4
   36:  invokestatic    #14; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
   39:  invokevirtual   #29; //Method scala/runtime/RichInt.compare:(I)I
   42:  goto    124
   45:  new #31; //class java/lang/Exception

   //part omitted for brevity..

   81:  aload_3
   82:  instanceof  #54; //class java/lang/Number
   85:  ifeq    161
   88:  aload_3
   89:  checkcast   #54; //class java/lang/Number
   92:  astore  6
   94:  aload   4
   96:  instanceof  #54; //class java/lang/Number
   99:  ifeq    125
   102: getstatic   #20; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   105: aload   6
   107: invokevirtual   #58; //Method java/lang/Number.doubleValue:()D
   110: invokevirtual   #62; //Method scala/Predef$.doubleWrapper:(D)Lscala/runtime/RichDouble;
   113: aload   4
   115: checkcast   #54; //class java/lang/Number
   118: invokevirtual   #58; //Method java/lang/Number.doubleValue:()D

6 , java.lang.Integer. , 81, java.lang.Number. , . , , 81 , 45, . . trac, , .

Edit Extempore, , trac, . .

+3

, :

def compare[A : Numeric, B: Numeric](first: A, second: B): Int =
  implicitly[Numeric[A]].toDouble(first) compare implicitly[Numeric[B]].toDouble(second)

scala> compare(0.0,1.0)
res30: Int = -1

scala> compare(0.0,1)
res31: Int = -1

scala> compare(0,1.0)
res32: Int = -1

scala> compare(0,1)
res33: Int = -1
+2

Source: https://habr.com/ru/post/1769162/


All Articles