开发者

Does Scala's 2.9.1 compiler throw away type parameter information?

开发者 https://www.devze.com 2023-04-12 13:41 出处:网络
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

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号