Подтвердить что ты не робот

"Тип параметра в структурном уточнении может не относиться к абстрактному типу, определенному вне этого уточнения"

Когда я компилирую:

object Test extends App {
  implicit def pimp[V](xs: Seq[V]) = new {
    def dummy(x: V) = x
  }
}                                                                                                                                                                                                              

Я получаю:

$ fsc -d aoeu go.scala
go.scala:3: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
    def dummy(x: V) = x
        ^
one error found

Почему?

(Scala: "Тип параметра в структурном уточнении может не ссылаться на абстрактный тип, определенный вне этого уточнения" на самом деле не отвечает на это.)

4b9b3361

Ответ 1

Он запрещен спецификацией. См. 3.2.7 Составные типы.

В объявлении метода в структурном переопределении тип любого параметра значения может ссылаться только на параметры типа или абстрактные типы, которые содержатся внутри исправления. То есть он должен ссылаться либо на параметр типа метода или определение типа в пределах исправления. Это ограничение не применяется к типу результата функций.

Прежде чем Ошибка 1906 был исправлен, компилятор скомпилировал бы это, и вы бы получили метод, не найденный во время выполнения. Это было исправлено в версия 19442, и именно поэтому вы получаете это замечательное сообщение.

Вопрос в том, почему это не разрешено?

Здесь очень подробное объяснение от Gilles Dubochet из списка рассылки scala еще в 2007 году. Это примерно сводится к тому, что структурные типы используют отражение, а компилятор не знает, как искать метод для вызова, если он использует тип, определенный вне уточнения (компилятор не знает заранее, как заполнить второй параметр getMethod в p.getClass.getMethod("pimp", Array(?))

Но посмотрите на сообщение, он ответит на ваш вопрос и еще несколько.

Edit:

Список приветствий.

Я пытаюсь определить структурные типы с абстрактным типом данных в функции параметр.... Любая причина?

Я слышал о двух вопросах, касающихся структурной типизации расширение scala 2.6 в последнее время, и я хотел бы ответить на них здесь.

  • Почему мы изменили scala собственные значения ( "int" и т.д.) схему бокса к Java ( "java.lang.Integer" ).
  • Почему ограничение на параметры для структурно определенных методы ("Тип параметра в структурной доработке не может ссылаться для абстрактного типа, определенного за пределами той же уточнения ").

Прежде чем ответить на эти два вопроса, мне нужно поговорить о реализация структурных типов.

Система типа JVM является очень простой (и соответствует Java 1.4). Что означает, что многие типы, которые могут быть представлены в scala, не могут быть представленный в виртуальной машине. Типы, зависящие от пути ( "x.y.A" ), одноточечные типы ( "a.type" ), составные типы ( "A с B" ) или абстрактные типы - все типы которые не могут быть представлены в системе типа JVM.

Чтобы скомпилировать байт-код JVM, компиляторы scala меняют Scala типы программы для их "стирания" (см. раздел 3.6 Справка). Стираемые типы могут быть представлены в системе типа VM и определить тип дисциплины в программе, которая эквивалентна типу программа, набранная с помощью типов scala (сохранение некоторых приведений), хотя и меньше точный. В качестве побочного примечания тот факт, что типы стираются в виртуальной машине объясняет, почему операции по динамическому представлению типов (шаблон сопоставление по типам) очень ограничены по отношению к типу scala система.

До сих пор все конструкции типа в scala могли быть удалены каким-то образом. Это не относится к структурным типам. Простой структурный тип "{def x: Int} "не может быть стерта до" Объекта ", поскольку виртуальная машина не позволит доступ к полю "x". Использование интерфейса "интерфейс X {int x {};}" поскольку стертый тип не будет работать либо потому, что любой экземпляр, связанный значение этого типа должно было бы реализовать тот интерфейс, который не может выполняться в присутствии отдельной компиляции. Действительно (медведь со мной) любой класс, который содержит член с тем же именем, что и член, определенный в структурный тип в любом месте должен был бы реализовать соответствующие интерфейс. К сожалению, этот класс может быть определен еще до известно, что существует структурный тип.

Вместо этого выполняется любая ссылка на структурно определенный элемент как отражающий вызов, полностью обходя систему типа VM. Для пример def f(p: { def x(q: Int): Int }) = p.x(4) будет переписан к чему-то вроде:

  def f(p: Object) = p.getClass.getMethod("x", Array(Int)).invoke(p, Array(4))

А теперь ответы.

  • "invoke" будет использовать значения boxed ( "java.lang.Integer" ), когда вызываемый метод использует собственные значения ( "int" ). Это означает, что вышеупомянутое вызов должен действительно выглядеть так: "... invoke (p, Array (new java.lang.Integer(4))). intValue".

Целочисленные значения в программе scala уже часто помещаются в бокс (чтобы разрешить "Любой" ), и было бы бесполезно распаковывать их из scala собственного бокс-схему, чтобы сразу же переустановить их как java.lang.Integer.

Хуже того, когда отражающий вызов имеет тип возврата "Любой", что должно быть сделано при возврате java.lang.Integer? Вызванный метод может либо возвращать "int" (в этом случае он должен быть unboxed и reboxbox как box scala), или он может возвращать java.lang.Integer, который следует оставить нетронутым.

Вместо этого мы решили изменить scala собственную схему бокса на Java. две предыдущие проблемы просто исчезают. Некоторые связанные с производительностью оптимизация у нас была с scala схемой бокса (предварительно вычислить коробочная форма наиболее распространенных номеров) были просты в использовании с Java бокс тоже. В конце концов, использование Java-бокса было даже немного быстрее, чем наша собственная схема.

  1. "getMethod" второй параметр - это массив с типами параметры (структурно определенного) метода поиска - для выбирая, какой метод получить, когда имя перегружено. Это одно место, где точные, статические типы необходимы в процессе перевод вызова структурного элемента. Обычно используемые статические типы для параметра метода предусмотрен структурный тип определение. В приведенном выше примере тип параметра "x" известен be "Int", что позволяет искать его.

Типы параметров, определенные как абстрактные типы, где абстрактный тип определенные в рамках структурной доработки, не являются проблемой или: def f (p: {def x [T] (t: T): Int}) = p.xInt В этом примере мы знаем, что любой экземпляр, переданный в "f" как "p", будет определите "x [T] (t: T)", который обязательно стирается до "x (t: Object)". поиск корректно выполняется по стираемому типу: def f (p: Object) = p.getClass.getMethod( "x", Array (Object)). invoke (p, Массив (новый java.lang.Integer(4)))

Но если абстрактный тип из-за пределов структурной доработки используется для определения параметра структурного метода, все ломается: def f [T] (p: {def x (t: T): Int}, t: T) = p.x(t) Когда вызывается "f" , "T" может быть создан для любого типа, например: f [Int] ({def x (t: Int) = t}, 4) f [Any] ({def x (t: Any) = 5}, 4) Поиск первого случая должен быть "getMethod (" x ", Array (int)) "и для второго" getMethod ( "x", Array (Object)) "и нет способа узнать, какой из них можно создать в теле "f" : "p.x(t)". ​​

Чтобы разрешить определение уникального вызова "getMethod" внутри тела "f" для любой экземпляр "T" потребовал бы, чтобы любой объект, переданный в "f" , Параметр "p" должен иметь тип "t", стертый до "Any". Это было бы где тип членов класса зависит от того, как экземпляры этого класса используются в программе. И это что-то мы определенно не хотим делать (и не может быть сделано с отдельными сборник).

В качестве альтернативы, если scala поддерживаемые типы времени выполнения, можно использовать их для решите эту проблему. Возможно, однажды...

Но теперь, используя абстрактные типы для параметра структурного метода типы просто запрещены.

С уважением, Жиль.

Ответ 2

Обнаружена проблема вскоре после публикации этого вопроса: я должен определить именованный класс вместо использования анонимного класса. (Тем не менее хотелось бы услышать лучшее объяснение рассуждений, хотя.)

object Test extends App {
  case class G[V](xs: Seq[V]) {
    def dummy(x: V) = x
  }
  implicit def pimp[V](xs: Seq[V]) = G(xs)
}                                                                                                                                                                                                              

работы.