Skip to content

Methods inherited from generic traits sometimes have types erased to Object #8905

Open
scala/scala
#7843
@scabug

Description

@scabug

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions