Ограничения параметра псевдонима типа не применяются во всех случаях

TL; DR: Похоже, что параметры типа псевдонимов типов (например, type T[X<:Serializable]) не применяют их ограничения, если они упоминаются как переменные, параметры и, возможно, другие случаи. Тем не менее, классы классов правильно применяют границы для своих параметров.

Рассмотрим псевдоним типа, предназначенный для представления подмножества родового типа. Например, скажем, я хочу тип для списков Serializable вещей:

scala> type SerializableList[T <: Serializable] = List[T]
defined type alias SerializableList

Теперь скажите, что я хочу класс case с параметром этих вещей:

scala> case class NetworkDataCC(things: SerializableList[_])
<console>:9: error: type arguments [_$1] do not conform to type SerializableList type parameter bounds [T <: Serializable]
   case class NetworkDataCC(things: SerializableList[_])

Ну, это не работает. Scala (досадно) не несет оценки параметров с типом, но легко исправить:

scala> case class NetworkDataCC(things: SerializableList[_ <: Serializable])
defined class NetworkDataCC

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

scala> class NetworkData(val things: SerializableList[_])
defined class NetworkData

Ой, подождите. Нет ошибки... да.

Итак, теперь я могу это сделать?

scala> new NetworkData(List(1))
res3: NetworkData = [email protected]

Хорошо, это кажется очень сломанным. Класс case, конечно, отлично работает (поскольку были объявлены ограничения):

scala> NetworkDataCC(List(1))
<console>:11: error: type mismatch;
 found   : Int(1)
 required: Serializable
              NetworkDataCC(List(1))

В моем проекте я использую отражение для генерации некоторых метаданных о моих классах. Метаданные для не-case-класса показывают отсутствие границ на things:

scala> classOf[NetworkData].getDeclaredFields()(0).getGenericType
res0: java.lang.reflect.Type = scala.collection.immutable.List<?>

В то время как класс case правильный:

scala> classOf[NetworkDataCC].getDeclaredFields()(0).getGenericType
res1: java.lang.reflect.Type = scala.collection.immutable.List<? extends scala.Serializable>

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

Ответ 1

Scala подчеркивание по умолчанию не равно SerializableList[X forSome {type X}]:

scala> def aa(a: SerializableList[_]) = a
aa: (a: SerializableList[_])List[Any]

scala> def aa(a: SerializableList[X forSome {type X}]) = a
<console>:11: error: type arguments [X forSome { type X }] do not conform to type SerializableList type parameter bounds [T <: Serializable]
   def aa(a: SerializableList[X forSome {type X}]) = a
             ^
scala> class NetworkDataCC(things: SerializableList[X forSome {type X}])
<console>:11: error: type arguments [X forSome { type X }] do not conform to typ
e SerializableList type parameter bounds [T <: Serializable]
   class NetworkDataCC(things: SerializableList[X forSome {type X}])

Это эквивалентно

scala> def aa(a: SerializableList[X] forSome {type X} ) = a
aa: (a: SerializableList[_])List[Any]

Итак, такое "неограниченное" поведение прекрасное. Проверьте этот ответ: fooobar.com/info/110407/...

В классах классов есть дополнительные ограничения типа (из-за эта ошибка, которая влияет на метод unapply, автоматически генерируемый для класса case).

Если вы хотите иметь "неограниченный" экзистенциальный тип в классе case, просто укажите тип более высокого порядка явно:

 scala> case class NetworkDataCC[SerializableList[_]](things: SerializableList[_])
 warning: there were 2 feature warning(s); re-run with -feature for details
 defined class NetworkDataCC

 scala> NetworkDataCC(List(1))
 res5: NetworkDataCC[List] = NetworkDataCC(List(1))

Или даже:

 scala> type SLL = SerializableList[_]
 defined type alias SLL

 scala> case class NetworkDataDD(things: SLL)
 defined class NetworkDataDD

Итак, это определенно ошибка, связанная с тем, что вы можете обойти ее с семантически эквивалентным псевдонимом типа (см. SI-8997)