Scala 3: Неполное совпадение для Vector, но не для Seq

Использование Scala 3.4.2:

Vector(1, 2, 3) match
  case Vector()  => println("empty")
  case _ :+ last => println(s"last: $last")

выдает мне (на мой взгляд неправильное) предупреждение о неисчерпывании

[warn] -- [E029] Pattern Match Exhaustivity Warning: ...
[warn] 5 |  Vector(1, 2, 3) match
[warn]   |  ^^^^^^^^^^^^^^^
[warn]   |match may not be exhaustive.
[warn]   |
[warn]   |It would fail on pattern case: Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*)

Если я использую Seq вместо Vector, код компилируется нормально.

Похоже, для Scala 3 это то же самое, что обсуждалось для Scala 2 в баге https://github.com/scala/bug/issues/12240.

Кроме того, это может относиться к https://github.com/scala/bug/issues/12252 с пометкой «исправлено в Scala 3».

Мои вопросы:

  1. Это настоящая ошибка в Scala 3?
  2. Если да, известно ли это где-нибудь/задокументировано, или мне следует создать новую заявку об ошибке?

Посмотрите другой вопрос, заданный сегодня: stackoverflow.com/questions/78720251/… - Если он не жалуется на Seq, то это либо ошибка, либо странная специальная обработка компилятора только для Seq. ИМХО, специальный регистр для компилятора - не очень хорошая идея, либо язык получит надлежащую функцию для определения пользовательских исчерпывающих проверок, в противном случае любое совпадение с шаблоном для чего-то, что не является ADT, должно считаться неисчерпывающим и возможным источником ошибок.

Luis Miguel Mejía Suárez 08.07.2024 22:12

Специального регистра нет: Vector — это запечатанный признак поэтому компилятор пытается доказать, что совпадение является исчерпывающим, Seq — это просто признак поэтому проверка исчерпываемости вообще не выполняется (поскольку компилятор НЕ проверяет для полноты во всех случаях, только в тех, где это вообще можно доказать).

Mateusz Kubuszok 10.07.2024 10:37

Что касается ошибки, речь идет о проверке полноты unapplySeq (чтобы компилятор мог проверить, что сопоставление vararg может исчерпать оставшиеся случаи). :+ не зависит от unapplySeq (с точки зрения компилятора), это другой случай.

Mateusz Kubuszok 10.07.2024 10:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. Поскольку спецификация Scala 3 еще не выпущена (на самом деле, она все еще находится в разработке), я буду использовать спецификацию Scala 2.13 (спецификация 2.13 + список изменений в Reference является ближайшим приближением спецификации Scala 3, которая у нас на данный момент есть):

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

    При упоминании исчерпывающих проверок упоминается только sealed. Во всем остальном поведение не определяется спецификацией, поэтому в лучшем случае оно зависит от реализации.

    В примечаниях к выпуску Scala 2.13.4 упоминается -Xlint:strict-unsealed-patmat флаг, который может добавить более исчерпывающие проверки.

    • Есть вероятность, что он где-то включен, например. если вы это сделаете -Xlint со всеми опциями или если у вас есть что-то вроде sbt-tpolecat, которое включает множество флагов
  2. Вектор — это запечатанный признак (в версии 2.13 и т. д. в Scala 3, поскольку он использует стандартную библиотеку версии 2.13)

  3. Seq это просто черта

  4. упомянутые вами ошибки связаны с исчерпывающими проверками unapplySeq, поэтому в основном такие вещи, как:

    Vector(1, 2, 3) match
      case Vector()  => println("empty")
      case Vector(multiple*) => println(s"last: ${multiple.last}")
    

    хотя +: там упоминалось как что-то, что должно быть подвергнуто анализу компилятором, это было скорее желанием - оно НЕ реализовано, и я ожидал, что оно никогда не будет реализовано, потому что это просто произвольное решение.

    object :+ {
      def unapply[A, CC[_] <: Seq[_], C <: SeqOps[A, CC, C]](t: C with SeqOps[A, CC, C]): Option[(A, C)] = ...
    }
    

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

Собираем все это вместе:

  • когда вы используете Seq, компилятор по умолчанию не пытается проверить полноту (с некоторым флагом -X это может быть возможно)
  • когда вы используете Vector, это sealed, поэтому он попытается доказать исчерпывающую проверку
  • улучшения компилятора позволяют обеспечить исчерпывающую проверку при использовании unapplySeq (case Vector(...) =>)
  • ни +:, ни :+ не являются Vector.unapplySeq, поэтому приведенные выше улучшения их не касаются, и они не исчерпывают никаких возможностей с точки зрения компилятора.
  • то, что вы наблюдаете, скорее всего, работает так, как задумано (в конце концов, спецификации Scala 3 не существует, поэтому мы не можем быть уверены, не спрашивая разработчиков), это вряд ли ошибка, даже если она не работает так, как вы надеетесь.

Другие вопросы по теме