Усовершенствованные дженерики в Scala 2.10 - PullRequest
27 голосов
/ 22 декабря 2011

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

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

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

Ответы [ 3 ]

31 голосов
/ 22 декабря 2011

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

  • усовершенствованные дженерики

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

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

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 в качестве параметра: т. Е. Тип стирания.

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

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

(*) У Kotlin сейчас есть демоверсия, и его реализация - пока что - просто синтаксический сахар для объединения манифестов и экземпляров тестов. Это все еще подчиняется тем же ограничениям, что и Scala.

8 голосов
/ 29 декабря 2015

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

Примеры модифицированных дженериков в Kotlin, знаменитом 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 голосов
/ 27 ноября 2012

Согласно тому, что говорит Андрей Бреслав на этой странице, Котлин не имеет овеществленных типов:

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

...