Есть ли у scala 3 псевдоним истинного типа? Как это реализовать?

Во многих учебниках и маркетинговых материалах по Scala я обнаружил, что многие люди злоупотребляют терминологией, смешивая «псевдоним типа» и «зависимый тип», хотя на самом деле это не одно и то же.

Например. в следующем примере TakeAlias является зависимым типом, а не псевдонимом типа. В результате это приведет к сбою компиляции:

object TrueTypeAlias {

  trait Unaliased[+T] {

    def take1: List[Seq[(T, T)]]

    def take2: List[Seq[(T, T)]]

    def take3: List[Seq[(T, T)]]
  }

  trait Aliased[+T] {

    type TakeAlias = List[Seq[(T, T)]]

    def take1: TakeAlias

    def take2: TakeAlias

    def take3: TakeAlias
  }
}

/*
TrueTypeAlias.scala:16:10: covariant type T occurs in invariant position in type  = List[Seq[(T, T)]] of type TakeAlias
one error found
*/

Проблема в том, что нужно для реализации псевдонима истинного типа? Есть ли механизм/расширение компилятора, которое я могу использовать, чтобы заставить его работать?

Это и псевдоним типа, и тип, зависящий от исправления, и ни один из них не связан с ошибкой компиляции. - Чтобы просто создать псевдоним типа, вы просто используете ключевое слово type в объекте или на верхнем уровне (только Scala 3)

Luis Miguel Mejía Suárez 02.05.2023 01:38

Ваш TakeAlias — это type-alias member черты Aliased, которая на самом деле является type-alias для typeList[Seq[(T, T)]]. Это то же самое, что иметь в Int value member имя i, имеющее значение 10. И поскольку этот type-alias является членом trait... тип, на который ссылается этот type-alias, также является path dependent type, поскольку он не может существовать и на него нельзя ссылаться без предварительной ссылки на trait instance.

sarveshseri 02.05.2023 12:47
Стоит ли изучать 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
2
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Нашел возможное решение:


object TrueTypeAlias {

  trait Unaliased[+T] {

    def take1: List[Seq[(T, T)]]

    def take2: List[Seq[(T, T)]]

    def take3: List[Seq[(T, T)]]
  }

  trait Aliased[+T] {

    private type TakeAlias = List[Seq[(T, T)]]

    def take1: TakeAlias

    def take2: TakeAlias

    def take3: TakeAlias
  }
}

В качестве альтернативы:


object TrueTypeAlias {

  trait Unaliased[+T] {

    def take1: List[Seq[(T, T)]]

    def take2: List[Seq[(T, T)]]

    def take3: List[Seq[(T, T)]]
  }

  trait Aliased[+T] {

    opaque type TakeAlias = List[Seq[(T, T)]]

    def take1: TakeAlias

    def take2: TakeAlias

    def take3: TakeAlias
  }

  trait Aliased2[+T] extends Aliased[T] {

    def take4: TakeAlias
  }
}
private фикс не работает в 2.13 scastie.scala-lang.org/DmytroMitin/iTBIyhmdQNmZLD1QcBJJTg
Dmytro Mitin 02.05.2023 13:46

Но private[this] работает scastie.scala-lang.org/DmytroMitin/iTBIyhmdQNmZLD1QcBJJTg/1 (как сказано в цитате из спецификации в моем ответе). private[this] отсутствует в Scala 3 docs.scala-lang.org/scala3/reference/dropped-features/…

Dmytro Mitin 02.05.2023 14:37

Возможно, в Scala 3 проверки отклонений были упрощены даже для private членов. Я не могу найти конкретный PR, документы или проблему. Возможно github.com/lampepfl/dotty/issues/7567 актуально

Dmytro Mitin 02.05.2023 14:43

@DmytroMitin Scala 3 автоматически превращает private в private[this], если элемент используется только как private[this]. Вы можете увидеть это, если добавите def foo(a: Aliased[?]): a.TakeAlias.

Jasper-M 02.05.2023 19:45

Всем большое спасибо за новую информацию. Извините, только что понял, что это не относится ни к какой логике, потому что дисперсия - это более доброе понятие. Удалить соответствующую часть

tribbloid 02.05.2023 21:50
Ответ принят как подходящий

type TakeAlias = List[Seq[(T, T)]] — это псевдоним типа в том смысле, что TakeAlias можно использовать вместо List[Seq[(T, T)]].

В то же время type TakeAlias = ... является типовым членом признака. Итак, x.TakeAlias (для x: Aliased[T]) — это тип, зависящий от пути. Хотя эта зависимость пути теперь тривиальна: x.TakeAlias одинаковы для разных x: Aliased[T] с одним и тем же T, а именно все x.TakeAlias являются List[Seq[(T, T)]]. А так как type TakeAlias = ... является членом типа, применяются все ограничения позиции отклонения.

Я бы исправил этот код, сделав псевдоним типа универсальным

trait Aliased[+T] {

  type TakeAlias[+S] = List[Seq[(S, S)]]
  //type TakeAlias[S] = List[Seq[(S, S)]]

  def take1: TakeAlias[T]

  def take2: TakeAlias[T]

  def take3: TakeAlias[T]

}

или извлечение псевдонима типа наружу (например, в компаньон)

trait Aliased[+T] {

  import Aliased.*

  def take1: TakeAlias[T]

  def take2: TakeAlias[T]

  def take3: TakeAlias[T]
}

object Aliased {
  type TakeAlias[+S] = List[Seq[(S, S)]]
  //type TakeAlias[S] = List[Seq[(S, S)]]
}

Цитата из спецификации:

https://scala-lang.org/files/archive/spec/2.13/04-basic-declarations-and-definitions.html#variance-annotations

  • Правая часть псевдонима типа всегда находится в неизменном положении.

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

Также, когда вы уверены, что незаконное использование не может привести к проблемам в вашем случае использования, вы можете использовать scala.annotation.unchecked.uncheckedVariance

trait Aliased[+T] {

  type TakeAlias = List[Seq[(T @uncheckedVariance, T @uncheckedVariance)]]

  def take1: TakeAlias

  def take2: TakeAlias
  
  def take3: TakeAlias

}

или

trait Aliased[+T] {

  type T1 = T @uncheckedVariance
 
  type TakeAlias = List[Seq[(T1, T1)]]

  def take1: TakeAlias

  def take2: TakeAlias

  def take3: TakeAlias

}

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