Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate methods due to type erasure in spite of @specialized

Stumbled over that

def foo(f: Int => Unit) {}
def foo(f: Long => Unit) {}

doesn't compile because of method foo is defined twice. I know that above is only a shorthand for

def foo(f: Function1[Int, Unit]) {}
def foo(f: Function1[Long, Unit]) {}

and that after type erasure both methods have same signature.

Now I've read in Try out specialized Function1/Function2 in 2.8.0 RC1! that Function1 and Function2 have @specialized versions for Int, Long and Double since Scala 2.8. That surely means that Function[Int, Unit] and Function[Long, Unit] have separate class files at JVM level.

Would then not both signatures are different?

Is the problem, that second type parameter will continue to be erased? But same problem with

class Bar[@specialized T]
def foo(f: Bar[Int]) {}
def foo(f: Bar[Long]) {}

it doesn't compile.

like image 934
binuWADa Avatar asked Nov 15 '11 09:11

binuWADa


1 Answers

@specialized has nothing to do with type erasure, at least in this case. It means that an extra version of your class is generated with the native type in the position. This saves on boxing/unboxing notably.

So you define a class like:

class MyClass[@specialized(Int) T] {
  def foobar(t: T) = {}
}

and you get two classes as output, (approximately):

class Foobar[java.lang.Object] {
  def foobar(t: java.lang.Object) = {}
}

class Foobar[int] {
  def foobar(t: int) = {}
}

You need to have two implementations of the class because you can't always guarantee that the one with the correct native type will be called. The scala compiler will choose which one to call. Note that the java compiler has no idea this specialization is taking place, so must call the unspecialized methods.

In fact, the output is the following (via JAD):

public class MyClass implements ScalaObject {
    public void foobar(Object obj) { }

    public void foobar$mcI$sp(int t) {
        foobar(BoxesRunTime.boxToInteger(t));
    }

    public MyClass() { }
}

public class MyClass$mcI$sp extends MyClass {
    public void foobar(int t) {
        foobar$mcI$sp(t);
    }

    public void foobar$mcI$sp(int i) { }

    public volatile void foobar(Object t) {
      foobar(BoxesRunTime.unboxToInt(t));
    }

    public MyClass$mcI$sp() {}
}

So your type erasure problem will not be fixed with @specialized.

like image 175
Matthew Farwell Avatar answered Sep 19 '22 12:09

Matthew Farwell