Можно ли в scala 2 использовать макрос или любую языковую функцию для переписывания механизма реификации абстрактного типа во всех подклассах? Как насчет Scala 3?
В scala 2 известно, что макросы строго локальны и выполняются только один раз, когда класс определен. Эта функция кажется особенно слабой при сочетании с абстрактным типом, поскольку процесс преобразования абстрактных типов в конкретный обычно обходит макрос и использует свои собственные примитивные правила.
Один простой пример, демонстрирующий противоречащий интуиции результат, представлен в следующем тестовом коде:
trait BB {
def ttag = implicitly[TypeTag[this.type]]
}
case class AA() extends BB
it("can TypeTag") {
val kk = AA()
TypeViz(kk.ttag).peek // this function visualise the full type tree of the type tag
}
в случае выполнения тип kk оказывается:
-+ BB.this.type
!-+ InfoCTSpec.this.BB
!-+ Object
!-- Any
К сожалению, тип AA полностью игнорируется, потому что
implicitly[TypeTag[this.type]]
поддерживается встроенным неявным макросом, который выполняется только ОДИН РАЗ, когда определен BB, а не когда определен AA и реифицирует фактическое
kk.this.type
. Я считаю его довольно громоздким и склонным к ухудшению некоторых других функций (например, сопоставление с образцом, лямбда-тип) из-за стирания типа во время выполнения.
Я хотел бы написать / использовать расширение языка, например, сделать
TypeTag[this.type]
подтип AA, БЕЗ введения накладных расходов времени выполнения и объектов контекста вне области видимости (так что БЕЗ ПОСЛЕДСТВИЯ). Как я могу сделать это с наименьшим количеством взлома? Я открыт для очень хардкорных решений, таких как расширение компилятора и макрос, но, очевидно, предпочтительнее элегантный обходной путь, который можно плавно перенести на scala 3/dotty.
PS похоже, что функция dotty «inline / compiletime» частично реализовала то, что я задумал. Это правильное впечатление?
1 ответ
Вы можете писать макросы и плагины компилятора, но обычный механизм для отсрочки неявного разрешения от сайта определения к сайту вызова заключается в замене
implicitly
с неявным параметром
trait BB {
def ttag(implicit tt: TypeTag[this.type]) = tt
}
Почему при неявном разрешении с параметрами типа имеет значение размещение val?
БЕЗ введения накладных расходов времени выполнения и объектов контекста вне области видимости (так что НЕ ПОДРАЗУМЕВАЕТСЯ).
Непонятно, почему вы хотите избежать имплицитов. Последствия разрешаются во время компиляции. Если вы замените это макросами или подключаемыми модулями компилятора, вы в любом случае разрешите имплициты вручную во время компиляции.