Пересечение дженериков Java и Scala ... не идет хорошо - PullRequest
4 голосов
/ 04 апреля 2019

Я свободно признаюсь, что был немного не в себе.Мое формальное обучение системам типов прошло несколько десятилетий.Я использовал дженерики в Java довольно тривиально, один или два раза, но я не могу утверждать, что они имеют глубокое и полное понимание.Я также относительный новичок в Scala, поэтому я не претендую на глубокое или полное понимание ее системы типов.

Я намеревался обновить свою реализацию XML Calabash v2, написанную на Scala (сегодня 2.12)) использовать саксонский 9.9.Саксонская 9.9 вводит дженерики в ряде мест.Меня устраивает.Я могу справиться, я думаю.

За исключением, я не могу, по-видимому.

Камень преткновения пытается реализовать класс, который расширяет класс ExtensionFunctionDefinition.Он имеет внутренний класс, который расширяет класс ExtensionFunctionCall.Это, в свою очередь, имеет абстрактный метод call, определенный таким образом в Java:

public abstract Sequence<?> call(
    XPathContext context,
    Sequence[] arguments
)

Моя первая попытка определить это в Scala была:

override def call(
    context: XPathContext,
    arguments: Array[Sequence]
): Sequence[_]

, но это неcompile: «trait Sequence принимает параметры типа».

Что верно:

public interface Sequence<T extends Item<?>>

(Item, кстати, равно:

public interface Item<T extends Item<?>>
extends GroundedValue<T>

, что я нахожу немного запутаннымпо другим причинам)

Для второй попытки я попытался:

override def call(
    context: XPathContext,
    arguments: Array[Sequence[_]]
): Sequence[_]

Но это, как мне сказали, ничего не отменяет.Харк, компилятор говорит:

[error] (Note that Array[net.sf.saxon.om.Sequence]
does not match Array[net.sf.saxon.om.Sequence[_]]:
their type parameters differ)

И здесь мы как будто зашли в тупик.Конечно, я могу просто реализовать эту проклятую вещь в Java, но действительно ли это ограничение в Scala или в моем понимании?

Кстати, я уже раньше лгал о своей первой попытке.Моя первая попытка была на самом деле:

override def call(
    context: XPathContext,
    arguments: Array[Sequence[_ <: Item[_ <: Item[_]]]]
): Sequence[_ <: Item[_ <: Item[_]]]

, которую я создал, прямо скопировав Java в Scala и позволив IntelliJ IDEA перевести его.Я не смог понять, что делать с рекурсивным характером объявления Item.

Ответы [ 3 ]

3 голосов
/ 04 апреля 2019

Это определенно компилируется (и тем самым подтверждает, что предложение Дмитрия Митина работает):

// ExtensionFunctionCall.java
public interface ExtensionFunctionCall {
  Sequence<?> call(String ctx, Sequence[] args);
}

// Item.java
public interface Item<T extends Item<?>> {}

// Sequence.java
public interface Sequence<T extends Item<?>> {}

// Impl.scala
class Impl extends ExtensionFunctionCall {
  override def call(
    ctx: String,
    args: Array[Sequence[_ <: Item[_]]]
  ): Sequence[_] = ???
}

Кстати, проблема не только в Скале. Если вы на секунду забудете Scala и попытаетесь внедрить его в Java, вы получите по существу те же ошибки:

class ImplJava implements ExtensionFunctionCall {
  public Sequence<?> call(
    String ctx,
    Sequence<?>[] args
  ) {
    return null;
  }
}

дает:

ImplJava.java:1: error: ImplJava is not abstract and does not override abstract method call(String,Sequence[]) in ExtensionFunctionCall
class ImplJava implements ExtensionFunctionCall {
^
ImplJava.java:2: error: name clash: call(String,Sequence<?>[]) in ImplJava and call(String,Sequence[]) in ExtensionFunctionCall have the same erasure, yet neither overrides the other
  public Sequence<?> call(
                     ^
2 errors

Теперь, это действительно загадочно, я не знаю, как записать этот тип в Java. Я не уверен, что это даже можно выразить в Java, не возвращаясь к 1.4-стилю. Sequence[] вещь просто зло, или, если цитировать эту замечательную статью, на которую ссылается Дмитрий Митин :

Сырые типы плохие. Прекратите использовать их

3 голосов
/ 04 апреля 2019

Попробуйте

override def call(context: XPathContext, arguments: Array[Sequence[_ <: Item[_]]]): Sequence[_] = ???
0 голосов
/ 04 апреля 2019

Я думаю, что Sequence без параметров типа в java преобразуется в Sequence[Foo], где Foo - максимально возможный супертип (Item в данном случае).Итак, я ожидаю, что что-то вроде этого будет работать:

override def call(context: XPathContext, arguments: Array[Sequence[Item[_]]]): Sequence[_] = ???
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...