5

既然 scala 已经迭代到使用 typeclass 的 JVM类型擦除修复ClassTag,为什么它是一个选择加入,而不是让编译器总是捕获类型签名以进行运行时检查。拥有一个隐式参数化类型约束将使得classTag[T]无论泛型参数声明如何都可以调用。

编辑:我应该澄清一下,我并不是说 scala 应该将幕后的签名更改为始终包含ClassTag。相反,我的意思是,既然ClassTag表明 scala 可以捕获运行时类型信息并因此避免类型擦除限制,为什么不能将该捕获作为编译器的一部分隐含,以便该信息始终在 scala 代码中可用?

我怀疑它与向后兼容性、Java 生态系统兼容性、二进制大小或运行时开销相关,但这些只是推测。

4

2 回答 2

3

向后兼容性将被完全破坏,真的。如果您有一个简单的方法,例如:

def foo[A](a: A)(implicit something: SomeType) = ???

那么假设在Scala的下一个版本中,编译器突然ClassTag在所有带类型参数的方法的签名中添加了隐式s。这种方法会被打破。任何被明确调用的地方foo(a)(someTypeValue)都不再起作用。二进制和源代码兼容性将消失。

Java 互操作性将是丑陋的。假设我们的方法现在看起来像这样:

def foo[A : ClassTag](a: A) = ???

因为ClassTags 是由 Scala 编译器生成的,所以在 Java 中使用这种方法会更加困难。你必须ClassTag自己创造。

ClassTag<MyClass> tag = scala.reflect.ClassTag$.MODULE$.apply(MyClass.class);
foo(a, tag);

我的 Java 可能不是 100% 正确,但你明白了。任何参数化的东西都会变得非常难看。好吧,如果它需要一个隐式的,它已经是了ClassTag,但是需要它的方法类会急剧增加。

此外,在我们(至少是我)使用的大多数参数化方法中,类型擦除并不是什么大问题。由于上述原因,我认为为每个类型参数自动要求一个ClassTag比它有帮助的麻烦得多。

当然,这会增加更多的编译器开销,因为它需要生成ClassTag比通常更多的 s。我认为除非有所作为,否则它不会增加更多的运行时开销ClassTag。例如,在像下面这样的简单方法中,ClassTag并没有真正做任何事情:

def foo[A : ClassTag](a: A): A = a

我们还应该注意到,它们也不完美。因此,添加它们并不是消除问题的最终解决方案。

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.

ClassTag向每个类实例添加 a会增加开销,并且肯定还会破坏兼容性。在很多地方也是不可能的。我们不能只注入java.lang.String一个ClassTag. 此外,我们仍然很容易被擦除。在每个类中都有一个ClassTag字段实际上并不比使用getClass. 我们可以进行类似的比较

case a if(a.getClass == classOf[String]) => a.asInstanceOf[String]

但这非常丑陋,需要演员阵容,而且不一定ClassTag是要解决的问题。如果我用我的find方法尝试这样的事情,它根本行不通。

// Can't compile
def find[A](l: List[Any]): Option[A] =
    l collectFirst { case a if(a.getClass == classOf[A]) => a.asInstanceOf[A] }

即使我要以某种方式与它一起工作ClassTag,它会从哪里来?我不能a.classTag == classTag[A],因为A已经被抹去了。我需要ClassTag在方法调用站点。

于 2015-05-17T23:43:19.850 回答
2

是的,对于很少见的用例(例如,需要数组构造或异构映射值恢复),您会惩罚任何通用方法或类。使用“始终是类标签”的想法,您还将有效地破坏从 Java 调用 Scala 代码的可能性。总之,从兼容性、性能或类大小的角度来看,要求始终存在类标记根本没有任何意义。

于 2015-05-18T01:02:45.493 回答