Now that scala has iterated towards a JVM type erasure fix with the ClassTag
typeclass, why is it an opt-in, rather than having the compiler always capture the type signature for runtime inspection. Having it an implicit parametrized type constraint would make it possible to call classTag[T]
regardless of the generic parameter declaration.
EDIT: I should clarify that I don't mean that scala should change the signature behind the scenes to always inlcude ClassTag
. Rather I mean that since ClassTag
shows that scala can capture runtime Type information and therefore avoid type erasure limitations, why can't that capture be implicit as part of the compiler so that that information is always available in scala code?
My suspicion is that it's backwards compatibility, java ecosystem compatibility, binary size or runtime overhead related, but those are just speculation.
Backwards compatibility would be completely destroyed, really. If you have a simple method like:
def foo[A](a: A)(implicit something: SomeType) = ???
Then suppose that in the next version of Scala, the compiler suddenly added implicit ClassTag
s to the signature of all methods with type parameters. This method would be broken. Anywhere it was being explicitly called like foo(a)(someTypeValue)
wouldn't work anymore. Binary and source compatibility would be gone.
Java interoperability would be ugly. Supposing our method now looks like this:
def foo[A : ClassTag](a: A) = ???
Because ClassTag
s are generated by the Scala compiler, using this method from Java would prove more difficult. You'd have to create the ClassTag
yourself.
ClassTag<MyClass> tag = scala.reflect.ClassTag$.MODULE$.apply(MyClass.class);
foo(a, tag);
My Java might not be 100% correct, but you get the idea. Anything parameterized would become very ugly. Well, it already is if it requires an implicit ClassTag
, but the class of methods where this would be necessary would increase dramatically.
Moreover, type erasure isn't that much of a problem in most parameterized methods we (I, at least) use. I think automatically requiring a ClassTag
for each type parameter would be far more trouble than it would help, for the above reasons.
Certainly this would add more compiler overhead, as it would need to generate more ClassTag
s than it usually would. I don't think it would add much more runtime overhead unless the ClassTag
makes a difference. For example, in a simple method like below, the ClassTag
doesn't really do anything:
def foo[A : ClassTag](a: A): A = a
We should also note that they're not perfect, either. So adding them isn't an end-all solution to erasure problems.
val list = List(1, "abc", List(1, 2, 3), List("a", "b"))
def find[A: ClassTag](l: List[Any]): Option[A] =
l collectFirst { case a: A => a }
scala> find[List[String]]
res2: Option[List[String]] = Some(List(1, 2, 3)) // Not quite! And no warnings, either.
Adding a ClassTag
to every single class instance would add overhead, and surely also break compatibility. It's also in many places not possible. We can't just infuse java.lang.String
with a ClassTag
. Furthermore, we'd still be just as susceptible to erasure. Having a ClassTag
field in each class is really no better than using getClass
. We could make comparisons like
case a if(a.getClass == classOf[String]) => a.asInstanceOf[String]
But this is horribly ugly, requires a cast, and isn't necessarily what the ClassTag
is meant to fix. If I tried something like this with my find
method, it wouldn't work--at all.
// Can't compile
def find[A](l: List[Any]): Option[A] =
l collectFirst { case a if(a.getClass == classOf[A]) => a.asInstanceOf[A] }
Even if I were to fashion this to somehow work with ClassTag
, where would it come from? I could not say a.classTag == classTag[A]
, because A
has already been erased. I need the ClassTag
at the method call site.
Yes, you would penalise any generic method or class for a use case that is quite seldom (e.g. requiring array construction or heterogeneous map value recovery). With this idea of "always class tags" you would also effectively destroy the possibility to call Scala code from Java. In summery, it simply doesn't make any sense to require a class tag to be always present, neither from compatibility, performance or class size point of view.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With