Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<blockquote> <p>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?</p> </blockquote> <p>Erasure precisely means that you lose any information about the type parameters of a generic class, and get only the raw type. So the signature of <code>def f[T](a: Array[T])</code> cannot be <code>def f[T](a: Array[Object])</code> because you still have a type parameter (<code>Object</code>). As a rule of thumb you just need to drop the type parameters to get the erase type, which would give us <code>def f[T](a: Array)</code>. This would work for all other generic classes, but arrays are special on the JVM, <strike>and in particular their erasure is simply <code>Object</code> (ther is no <code>array</code> raw type). And thus the signature of <code>f</code> after erasure is indeed <code>def f[T](a: Object)</code>.</strike> <strong>[Updated, I was wrong]</strong> Actually after checking the java spec, it appears that I was completly wrong here. The spec says </p> <blockquote> <p>The erasure of an array type T[] is |T|[]</p> </blockquote> <p>Where <code>|T|</code> is the erasure of <code>T</code>. So, indeed arrays are treated specially, but the peculiar thing is that the while the type parameters are indeed removed, the type is marked as being an array of T instead of just T. This means that <code>Array[Int]</code> is, after erasure still <code>Array[Int]</code>. But <code>Array[T]</code> is different: <code>T</code> is a type parameter for the generic method <code>f</code>. In order to be able to treat any kind of array generically, scala has no other choice than turning <code>Array[T]</code> into <code>Object</code> (and I suppose Java does just the same by the way). This is because as I said above there is no such thing as a raw type <code>Array</code>, so it has to be <code>Object</code>. </p> <p>I'll try to put it another way. Normally when compiling a generic method with a parameter of type <code>MyGenericClass[T]</code>, the mere fact that the erased type is <code>MyGenericClass</code> makes it possible (at the JVM level) to pass any instantiation of <code>MyGenericClass</code>, such as <code>MyGenericClass[Int]</code> and <code>MyGenericClass[Float]</code>, because they are actually all the same at runtime. However, this is not true for arrays: <code>Array[Int]</code> is a completly unrelated type to <code>Array[Float]</code>, and they won't erase to a common <code>Array</code> raw type. Their least common type is <code>Object</code>, and so this is what is manipulated under the hood when arrays are treated generically (everythime the compiler cannot know statically the type of elements).</p> <p><strong>UPDATE 2</strong>: v6ak's answer added a useful bit of information: Java does not support primitive types in generics. So in <code>Array[T]</code>, <code>T</code> is necessarily (in Java, but not in Scala) a sub-class of <code>Object</code> and thus its erasure to <code>Array[Object]</code>totally makes sense, unlike in Scala where <code>T</code> can by example be the primitive type <code>Int</code>, which is definitly not a sublclass of <code>Object</code> (aka <code>AnyRef</code>). To be in the same situation as Java, we can constrain <code>T</code> with an upper bound, and sure enough, now it compiles fine:</p> <pre><code>def f[T](t: T) = println("normal type") def f[T&lt;:AnyRef](a: Array[T]) = println("Array type") // no conflict anymore </code></pre> <p>As to how you can work around the problem, a common solution is to add a dummy parameter. Because you certainly don't want to explicitly pass a dummy value on each call, you can either give it a dummy default value, or use an implicit parameter that will always be implicitly found by the compiler (such as <code>dummyImplicit</code> found in <code>Predef</code>):</p> <pre><code>def f[T](a: Array[T], dummy: Int = 0) // or: def f[T](a: Array[T])(implicit dummy: DummyImplicit) // or: def f[T:ClassManifest](a: Array[T]) </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload