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)
You can't cast
Double
toInteger
anyway (because it's boxed).Numeric
just allows you to have a set of mathematical operations (byimport num._
) on your T - nothing else (you don't need some mediate type for that). A2 works only because println expectingAny
as a result off(3)
, soT
is automatically inferred toAny
;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:
The reason why you can't just do
result.doubleValue.asInstanceOf[A]
here is that A is already boxed.@specialized
annotation doesn't work forasInstanceOf
(type A is still boxed)UPDATE: actually
@specialized
works:But it doesn't work in Scala REPL - so be careful!
P.S. Manifests are deprecated: use
classTag
/typeTag
instead