На самом деле обратная совместимость будет полностью уничтожена. Если у вас есть простой метод, например:
def foo[A](a: A)(implicit something: SomeType) = ???
Затем предположим, что в следующей версии Scala компилятор вдруг добавил неявные ClassTag в сигнатуру всех методов с параметрами типа. Этот метод будет нарушен. Везде, где он явно вызывался, как foo(a)(someTypeValue), больше не будет работать. Двоичная и исходная совместимость исчезнет.
Совместимость с Java была бы уродливой. Предположим, что наш метод теперь выглядит так:
def foo[A : ClassTag](a: A) = ???
Поскольку ClassTag создаются компилятором Scala, использовать этот метод из Java будет сложнее. Вам придется создать ClassTag самостоятельно.
ClassTag<MyClass> tag = scala.reflect.ClassTag$.MODULE$.apply(MyClass.class);
foo(a, tag);
Моя Java может быть не на 100% правильной, но вы поняли. Все, что параметризовано, станет очень уродливым. Ну, это уже так, если для этого требуется неявный ClassTag, но класс методов, где это было бы необходимо, резко увеличился бы.
Кроме того, стирание типов не является большой проблемой в большинстве параметризованных методов, которые мы (по крайней мере, я) используем. Я думаю, что автоматическое требование ClassTag для каждого параметра типа было бы гораздо более проблематичным, чем помогло бы, по вышеуказанным причинам.
Конечно, это добавит дополнительных накладных расходов компилятору, так как потребуется генерировать больше ClassTags, чем обычно. Я не думаю, что это добавит гораздо больше накладных расходов во время выполнения, если только 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 к каждому отдельному экземпляру класса добавит накладные расходы и, конечно же, нарушит совместимость. Это также во многих местах невозможно. Мы не можем просто смешать 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 на сайте вызова метода.
person
Michael Zajac
schedule
17.05.2015