Description
It seems that methods inherited from generic traits sometimes have their types erased to Object, which causes compilation or runtime errors when calling these methods from Java. This seems like it it might be related to #3452.
Here's a simple reproduction (also available as a gist with a build.sbt, in case you want to clone it to quickly test this out):
In Scala:
import java.util.Comparator
trait RDDLike[T] {
def max(comp: Comparator[T]): T = {
(1.0).asInstanceOf[T]
}
}
class DoubleRDD extends RDDLike[java.lang.Double] { }
In Java:
import java.util.Comparator;
public class Test {
private static class DoubleComparator implements Comparator<Double> {
public int compare(Double o1, Double o2) {
return o1.compareTo(o2);
}
}
public static void main(String[] args) {
DoubleRDD rdd = new DoubleRDD();
RDDLike<Double> rddLike = rdd;
// This call works fine:
double rddLikeMax = rddLike.max(new DoubleComparator());
// In Scala 2.10.4, this code compiles but this call fails at runtime:
// java.lang.NoSuchMethodError: DoubleRDD.max(Ljava/util/Comparator;)Ljava/lang/Double;
double rddMax = rdd.max(new DoubleComparator());
}
}
In Scala 2.10.4, this code compiles fine but throws a NoSuchMethodError at runtime when I call the max
method via the DoubleRDD
class. In all versions of Scala 2.11 that I've tested, the Java code fails to compile:
error: incompatible types
[error] double rddMax = rdd.max(new DoubleComparator());
[error] ^
[error] required: double
[error] found: Object
[error] 1 error
Based on javap
, it seems that Scala 2.10.4 emits the right signature for DoubleRDD.max:
javap -s target/scala-2.10/classes/DoubleRDD.class
Compiled from "RDD.scala"
public class DoubleRDD implements RDDLike<java.lang.Double> {
public java.lang.Double max(java.util.Comparator<java.lang.Double>);
Signature: (Ljava/util/Comparator;)Ljava/lang/Object;
public DoubleRDD();
Signature: ()V
}
Scala 2.11.2 seems to erase to Object:
javap -s target/scala-2.11/classes/DoubleRDD.class
Compiled from "RDD.scala"
public class DoubleRDD implements RDDLike<java.lang.Double> {
public java.lang.Object max(java.util.Comparator);
Signature: (Ljava/util/Comparator;)Ljava/lang/Object;
public DoubleRDD();
Signature: ()V
}
However, if I override the implementation of the max
method in my class, then everything works fine. This compiles and runs as expected:
class DoubleRDD extends RDDLike[java.lang.Double] {
override def max(comp: Comparator[java.lang.Double]): java.lang.Double = {
(1.0).asInstanceOf[java.lang.Double]
}
}
Surprisingly, though, the generated bytecode now contains two max
methods:
javap -s target/scala-2.10/classes/DoubleRDD.class
Compiled from "RDD.scala"
public class DoubleRDD implements RDDLike<java.lang.Double> {
public java.lang.Double max(java.util.Comparator<java.lang.Double>);
Signature: (Ljava/util/Comparator;)Ljava/lang/Double;
public java.lang.Object max(java.util.Comparator);
Signature: (Ljava/util/Comparator;)Ljava/lang/Object;
public DoubleRDD();
Signature: ()V
}
This happens in both 2.10.4 and 2.11.2.