Когда именно происходит стирание типа? - PullRequest
3 голосов
/ 28 февраля 2012

Синтаксис scala очень многообещающий. Первоначально я думал, что scala - это больше, чем просто удобная java, и он может вводить совершенно новую парадигму программирования, но многие возможности, допускаемые синтаксисом, неверны в семантике. Поэтому я начал поиски ограничений для scala и хаков для их устранения. Хотя я просто пишу тестовый проект, чтобы приспособиться к способам и моделям скала с другой точки зрения.

Основным препятствием является стирание типа, унаследованное от реализации jvm. Я могу написать небольшую статью под названием «Десять красивых шаблонов, которые уничтожило стирание шрифтов». Говорят, что стирание типов портит дженерики, но я наткнулся на стирание типов в миксинах. Я считаю это проблемой с реализацией миксина в scala.

Преамбула

trait T1
trait T2

trait B1 {
  def typeMe(x:T1){}
}

Сломанный код с миксинами

trait B2 extends B1 {
  def typeMe(x:T1 with T2) {}
}

Рабочий код с миксином, объявленным как отдельная черта

trait T3 extends T1 with T2
trait B3 extends B1 {
  def typeMe(x:T3) {}
}

Ошибка:

error: name clash between defined and inherited member:
method typeMe:(x: T1 with T2)Unit and
method typeMe:(x: T1)Unit in trait B1
have same type after erasure: (x: $line12.$read#$iw#$iw#T1)Unit
    def typeMe(x:T1 with T2)

Какой лучший обходной путь доступен? Введение новой черты является многословным (особенно для больших цепочек миксинов) и приводит к несовместимости типов. Добавление фиктивных неявных аргументов также не является серебряной пулей, поскольку увеличивает накладные расходы.


обновление:

Мне очень жаль, я задал неправильный вопрос. Меня больше интересует природа описанной ошибки, а не ее обходные пути. Где происходит стирание типа? Я не вижу обобщений в коде, который считается источником стирания типа. Какая механика стоит за поведением компилятора?

1 Ответ

3 голосов
/ 28 февраля 2012

Есть пара проблем с тем, что вы пытаетесь сделать.

Во-первых, не имеет значения, когда происходит стирание типа. Это связано с тем, что концепция стирания типов заключается в том, что независимо от того, стираете ли вы типы до или после вычисления, результат должен быть одинаковым. Для языков JVM некоторое стирание происходит во время компиляции, iinm.

Во-вторых, ваш «рабочий» код на самом деле не работает так, как вы думаете. Это требует небольшого понимания субтипирования, ковариации и контравариантности. (Foo <: Bar означает «Foo является подтипом Bar» или неофициально, что «Foo является более конкретным, чем Bar»). Функции являются контравариантными по своему входу и ковариантными по своему выходу, что означает, что функция A => B <: W => V только если W <: A и B <: V.

Теперь рассмотрим ваши функции:

B1.typeMe(x:T1)
B3.typeMe(x:T3)

Ввод для B3.typeMe - T3, а тип ввода для B1.typeMe - T1. Однако T3 <: T1 (T3 более конкретно , чем T1), поэтому тип B3.typeMe не может быть подтипом типа B1.typeMe. Вместо этого они просто считаются отдельными функциями, иногда происходит какое-то жуткое безмолвное дублирование. Вообще-то, честно говоря, это должно выдавать ошибку или, по крайней мере, предупреждение. К счастью, другая версия делает.

...