Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type erasure with parameter defaults

The following does not compile:

package play

object Stats2 {
  def variance(data: Seq[Double], dof: Int = 0): Double = {
    println("variance Double direct"); 1.0
  }
  def variance[T](data:Seq[T], dof: Int = 0)(implicit ex: T => Double): Double = {
    println("variance Double extracted"); 1.0
  }
} 

The compiler says:

$ scalac erasure2.scala 
erasure2.scala:7: error: double definition:
method variance$default$2:[T]=> Int and
method variance$default$2:=> Int at line 4
have same type after erasure: ()Int
  def variance[T](data:Seq[T], dof: Int = 0)(implicit ex: T => Double): Double = {
                               ^
one error found

If dof :Int = 0 is changed to dof: Int, the example compiles and works as expected.

It seems ugly that the presence or absence of a default parameter value changes whether the code is valid or not.

What is the explanation for why this really makes sense?

like image 995
Mike Hanafey Avatar asked Sep 18 '13 15:09

Mike Hanafey


1 Answers

The problem is that when you use default arguments, its name and the method name is used to generate a static attribute, this way: [methodName]$default$[argumentPosition], in your case it will be variance$default$2, so if both have default arguments, the compiler will try to generate 2 static attributes with the same name.

if the type of the other arguments in the method were used, this could be avoided. You may submit a SIP Proposal to change this behaviour in the compiler.

You can read more about this on this post

If you want to check by yourself, try compiling your object with each method and inspect the class using javap [XXX], where is the name of the object or class, in your case javap Stats2.
Your first method will give:

public final class Stats2 extends java.lang.Object{
    public static final int variance$default$2();
    public static final double variance(scala.collection.Seq, int);
}

and your second method will give:

public final class Stats2 extends java.lang.Object{
    public static final int variance$default$2();
    public static final double variance(scala.collection.Seq, int, scala.Function1);
}

finally, by removing the default value for dof in the second method, we get:

public final class Stats2 extends java.lang.Object{
    public static final double variance(scala.collection.Seq, int, scala.Function1);
}

So the static final int variance$default$2() is what is making the compilation to fail, which is generated by the default value.

like image 192
Vinicius Miana Avatar answered Oct 14 '22 11:10

Vinicius Miana