Обоснованные дженерики в Scala 2.10

Отсутствие редифицированных дженериков в Scala - это то, что больше всего меня беспокоит языком, поскольку простые вещи не могут быть реализованы без использования сложных конструкций.

Оба Kotlin и Ceylon поддерживают реинфицированные дженерики, поэтому его можно сделать на вершине JVM. В прошлом было сказано, что Scala не может поддерживать их без изменения JVM, но теперь Scala 2.10 по слухам, чтобы иметь ограниченную поддержку для овеществления. Поэтому мой вопрос:

  • Что мы можем ожидать для reification в Scala 2.10, я, например, смогу реализовать универсальный признак несколько раз?. Насколько он ограничен?
  • Если Scala 2.10 reification оказывается более ограниченным, чем Kotlin и Цейлон. Почему это?

Ответы

Ответ 1

Ваш аргумент неверен. Kotlin еще не выпущен *, и Ceylon только что выпустил свою первую версию, и я приведу одну из вещей, которые она отсутствует в их объявлении:

  • reified generics

Итак, извините, но какая реализация доказывает, что это возможно? На самом деле, я не очень много смотрю на то, что Котлин обещает, но то, что Цейлон многообещающе, - это то, что уже проявляются, но прозрачным образом.

Но рассмотрим проблему, которую вы описали в своем вопросе:

trait Handles[E <: Event] {
  def handle(event: E)
}

Итак, в первую очередь, JVM не предоставляет никакого способа идентификации параметров типа в интерфейсах или классах, поэтому E не может быть проверен JVM. Однако вы можете хранить информацию о том, что означает E в каждом объекте, реализующем Handles, так же, как вы могли бы написать это в Scala:

abstract class Handles[E <: Event : Manifest] {
  def handle(event: E)
}

Затем рассмотрим метод handle. Опять же, JVM не дает возможности использовать параметры типа в определении метода. Единственный способ реализовать это состоит в том, чтобы handle принять Object в качестве параметра: ie, type erasure.

И вот сделка: чтобы сделать handle вызываемым с Java, он должен быть стираться. И, если тип стирается, тогда это подлежит ограничению, описанному в вашем вопросе. Единственный способ обойти это - отказаться от совместимости с Java (которая, кстати, недоступна и в первой версии Ceylon).

Да, Scala будет охарактеризовать (что-то вроде) на 2.10, по словам Мартина Одерского. Но независимо от того, что он предоставляет (и я делаю ставку на более прозрачное использование манифестов для утверждения равенства типов), это конкретное ограничение является неотъемлемой частью JVM и не может быть преодолено без потери интеграции Java.

(*) Теперь у Kotlin есть демоверсия, и ее reification - до сих пор - это просто синтаксический сахар для связывания манифеста и тестов instanceOf. Он по-прежнему подвержен тем же ограничениям Scala.

Ответ 2

Kotlin обновил дженерики для параметров типа встроенных функций, как описано здесь: https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters. Это уже давно существует в Котлине, они используются многими библиотеками уже в экосистеме Котлин. Другие ответы здесь устарели, когда речь идет о Котлине. Kotlin был выпущен как 1.0 с февраля 2016 года.

Примеры повторяющихся дженериков в Котлине, знаменитый TypeReference в Джексоне, когда он используется в модуле Джексона Котлина, использует этот код:

public inline fun <reified T: Any> ObjectMapper.readValue(jp: JsonParser): T 
     = readValue(jp, object: TypeReference<T>() {})

И то же самое с библиотекой Injekt от Kotlin:

public inline fun <reified T: Any> fullType(): FullTypeReference<T> 
    = object:FullTypeReference<T>(){}

public inline fun <reified T : Any> injectLazy(): Lazy<T> {
    return lazy { Injekt.get(fullType<T>()) }
}

Ответ 3

В соответствии с тем, что говорит Андрей Бреслав на этой странице Kotlin не имеет типов reified:

"Да, параметры типа недоступны в объектах класса"