I’d like to write overloaded functions as follows:
case class A[T](t: T)
def f[T](t: T) = println("normal type")
def f[T](a: A[T]) = println("A type")
And the result is as I expected:
f(5) => normal type
f(A(5)) => A type
So far so good. But the problem is the same thing doesn’t work for Arrays:
def f[T](t: T) = println("normal type")
def f[T](a: Array[T]) = println("Array type")
Now the compiler complains:
double definition: method f:[T](t: Array[T])Unit and method f:[T](t: T)Unit at line 14 have same type after erasure: (t: java.lang.Object)Unit
I think the signature of the second function after type erasure should be (a: Array[Object])Unit not (t: Object)Unit, so they shouldn’t collide with each other. What am I missing here?
And if I’m doing something wrong, what would be the right way to write f’s so that the right one will get called according to the type of the argument?
This is never an issue in Java, because it does not support primitive types in generics. Thus, following code is pretty legal in Java:
On the other hand, Scala supports generics for all types. Although Scala language does not have primitives, the resulting bytecode uses them for types like Int, Float, Char and Boolean. It makes the difference between the Java code and Scala code. The Java code does not accept
int[]as an array, becauseintis not anjava.lang.Object. So Java can erase these method parameter types toObjectandObject[]. (That meansLjava/lang/Object;and[Ljava/lang/Object;on JVM.)On the other hand, your Scala code handles all arrays, including
Array[Int],Array[Float],Array[Char],Array[Boolean]and so on. These arrays are (or can be) arrays of primitive types. They can’t be casted toArray[Object]orArray[anything else]on the JVM level. There is exactly one supertype ofArray[Int]andArray[Char]: it isjava.lang.Object. It is more general supertype that you may wish to have.To support these statements, I’ve written a code with less generic method f:
This variant works like the Java code. That means, array of primitives aren’t supported. But this small change is enough to get it compiled. On the other hand, following code can’t be compiled for the type erasure reason:
Adding @specialized does not solve the problem, because a generic method is generated:
I hope that @specialized might have solved the problem (in some cases), but compiler does not support it at the moment. But I don’t think that it would be a high priority enhancement of scalac.