Почему классы значений ограничены AnyVal?
Насколько я понимаю, классы значений в Scala существуют только для того, чтобы переносить примитивные типы, такие как Int
или Boolean
, в другой тип без дополнительного использования памяти. Поэтому они в основном используются как легкая альтернатива обычным классам.
Это напоминает мне нотацию Хаскелла newtype
, которая также используется для обертывания существующих типов в новые, таким образом вводя новый интерфейс к некоторым данным без использования дополнительного пространства (чтобы увидеть сходство обоих языков рассмотрим например, ограничение на один "конструктор" с одним полем как в Haskell, так и в Scala).
AnyVal
)?
Или в Scala уже есть способ также определить такие оболочки для типов Scala.AnyRef
?
2 ответа:
Они не ограничиваются
AnyVal
.Существуют различные ограничения на классы значений, которые заставляют их действовать как легкие оболочки, но только возможность обернуть примитивы не является одним из них.implicit class RichOptionPair[A,B](val o: Option[(A,B)]) extends AnyVal { def ofold[C](f: (A,B) => C) = o map { case (a,b) => f(a,b) } } scala> Some("fish",5).ofold(_ * _) res0: Option[String] = Some(fishfishfishfishfish)
Аргументация документируется какпроцесс улучшения Scala (SIP)-15 . Как отметил в своем комментарии Алексей Романов, идея состояла в том, чтобы искать выражение, используя существующие ключевые слова, которые позволили бы компилятору определить эту ситуацию.
Для выполнения компилятором инлайнинга применяется несколько ограничений, например, класс обертывания является "эфемерным" (нет поля или объекта-члена, тела конструктора и т. д.). Ваше предложение о автоматической генерации инлайнинга классы имеют по крайней мере две проблемы:
Компилятор должен будет пройти через весь список ограничений для каждого класса. А поскольку класс status as value неявен, он может перевернуться, добавив члены в класс в более поздний момент, нарушая двоичную совместимость
- дополнительные ограничения добавляются компилятором, например, класс значение становится
final
, запрещающие наследование. Таким образом, вы должны были бы добавить эти ограничения к любому классу, который хочет быть inlineable таким образом, а затем вы не получаете ничего, кроме дополнительного многословия.Можно было бы придумать и другие гипотетические конструкции, например
val class Meter(underlying: Double) { ... }
, но преимуществоextends AnyVal
IMO заключается в том, что не требуется никаких синтаксических расширений. Кроме того, все примитивные типы расширяютсяAnyVal
, поэтому есть хорошая аналогия (нет ссылки, нет наследования, эффективного представления и т. д.)