Does Scala's 2.9.1 compiler throw away type parameter information?
I'm writing some Java code that depends on some Scala code (that I have also written). Trying to supply an argument with a parameterized type seems to work if the Scala is compiled with 2.8.0 but fail if I use 2.9.1.
The (simplified) Scala code looks roughly like this:
package test
import collection.JavaConversions._
class SomeClass {
def foo(numbers: java.util.Set[Long]) {
numbers.foreach(println(_))
}
}
This compiles happily with both the 2.8.0 and 2.9.1 compilers. The Java code looks something like this:
package test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class App {
public static void main(String[] args) {
new SomeClass().foo(new HashSet<Long>(A开发者_Go百科rrays.asList(1L, 2L, 3L)));
}
}
If I compile the Scala with the 2.8.0 compiler, then the Java will compile happily (with Java's 1.6.0_26 compiler). However, if I compile the Scala with 2.9.1, then the Java compiler fails with the error:
test\App.java:16: foo(java.util.Set<java.lang.Object>) in test.SomeClass cannot be applied to (java.util.HashSet<java.lang.Long>)
sc.foo(new HashSet<Long>(Arrays.asList(1L, 2L, 3L)));
^
1 error
So it seems that while Scala 2.8.0 retains in the bytecode the information that numbers
is of type Set<Long>
, the 2.9.1 compiler emits bytecode where numbers
is a Set<Object>
.
Is this a bug? Is it an unfortunate (for me) side-effect of a deliberate change? (The Scala changelog mentions "various fixes in ... JavaConversions
for smoother interoperation"). If so, is there anything I can do to get this to work with 2.9.1?
Ok, as my shot in the dark in comment proved lucky, same as an answer.
It works with
def foo(numbers: java.util.Set[java.lang.Long])
java.lang.Long
is not the same as the Long
of scala. Notably, Set[java.lang.Long]
can contain null
, a Set[Long]
should not (unless the type system was circumvented with some sort of unchecked cast). This is in spite of the Set
being implemented as containing references in both case; in the second case, they are guaranteed to be non null.
Identifying Set[Long]
and Set[java.lang.Long]
opens a loophole in the type system. That being said, I don't know whether the change was intended.
Short answer, it's complicated. Any
in the Scala type system is a great unifier, but a complete fiction by the time you're in Java-land.
The simplified view taken prior to 2.9 was ill-conceived and broke things.
To get a feel for the rock-and-a-hard-place nature of the problem, read Paul Phillips' accounts from the mailing lists:
http://www.scala-lang.org/node/9157
http://www.scala-lang.org/node/8888
http://www.scala-lang.org/node/8980
精彩评论