Scala cast to generic type (for generic numerical function)

casting, generics, scala, scala-java-interop

Solution

You can't cast `Double` to `Integer` anyway (because it's boxed). `Numeric` just allows you to have a set of mathematical operations (by `import num._`) on your T - nothing else (you don't need some mediate type for that). A2 works only because println expecting `Any` as a result of `f(3)`, so `T` is automatically inferred to `Any`; `println(f[Int](3))` will never work, `f[Any](3)` will always work.

If you want to implement generic function which operates Doubles (you may need that only if you have operations specific to Double) - you should better return Double. If you can't - you will have to construct the type manually by analizing T:

def f[A](x: A)(implicit num: Numeric[A]): A = {
   val result = new java.lang.Double(num.toDouble(x))
   (x match {
       case x: Double => result
       case x: Int => result.toInt
       case x: Float => result.toFloat
       case x: Long => result.toLong
   }).asInstanceOf[A]
}

The reason why you can't just do `result.doubleValue.asInstanceOf[A]` here is that A is already boxed. `@specialized` annotation doesn't work for `asInstanceOf` (type A is still boxed)

UPDATE: actually `@specialized` works:

def f[@specialized(Int, Double, Long, Float) A](x: A)(implicit num: Numeric[A]): A = {
   val result = new java.lang.Double(num.toDouble(x)) 

   result.doubleValue.asInstanceOf[A]
}

But it doesn't work in Scala REPL - so be careful!

P.S. Manifests are deprecated: use `classTag`/`typeTag` instead

Problem

I'm trying to implement a generic function that wraps a mathematical Java function. For simplicity, we can assume that the Java function (Java 7) takes one parameter and returns a result, both of type java.lang.Double. Of course, the wrapper function should take a parameter and a result, both of generic but numeric type A. The problem is that I'm not able to cast the result back to type A in the wrapper function. Where/what is the problem? Note: (I'm a newbie on Scala and used the following reference to solve the problem.) - I'm using implicit type trait Numeric to enforce that template types are numeric. How do I implement a generic mathematical function in Scala - I found 'import scala.collection.JavaConversions._' which I do not fully understand, but it seems to me that it's rather for conversion of Java collections and doesn't solve my problem, does it? Iterating over Java collections in Scala - As described here, I tried to use Manifest to enforce correct casting (Variant B) which, however, ends up in an exception java.lang.ClassCastException. Scala asInstanceOf with parameterized types Variant A ``` package test object mytest { def f[A](x: A)(implicit num: Numeric[A]): A = { val result = new java.lang.Double(num.toDouble(x)) result.asInstanceOf[A] } def main(args: Array[String]) { // 'Some code' } } ``` 'Some code' A1 ``` result val result = f(3) ``` Output: ``` Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105) at test.mytest$.main(test.scala:10) at test.mytest.main(test.scala) ``` 'Some code' A2 ``` println(f(3)) ``` Output: ``` 3.0 ``` 'Some code' A3 ``` println(f(3).getClass) ``` Output: ``` int ``` Variant B ``` package test object mytest { def f[A : Manifest](x: A)(implicit num: Numeric[A]): A = { val result = new java.lang.Double(num.toDouble(x)) manifest[A].erasure.cast(result).asInstanceOf[A] } def main(args: Array[String]) { val result = f(3) } } ``` Output: (This is the same also for equivalents of variants A1, A2, and A3, because the exception is now thrown in line 6 of function f.) ``` Exception in thread "main" java.lang.ClassCastException: Cannot cast java.lang.Double to int at java.lang.Class.cast(Class.java:3176) at test.mytest$.f(test.scala:6) at test.mytest$.main(test.scala:10) at test.mytest.main(test.scala) ```

Original source

Related problems