Типобезопасные примитивы в Scala - PullRequest
8 голосов
/ 21 ноября 2010

Я хотел бы иметь в своем коде Scala безопасные для типов «подклассы» примитивов без снижения производительности (для приложений с очень малой задержкой). Например, что-то вроде этого:

class Timestamp extends Long
class ProductId extends Long

def process(timestamp: Timestamp, productId: ProductId) {
  ...
}

val timestamp = 1: Timestamp // should not box
val productId = 1: ProductId // should not box

process(timestamp, productId) // should compile
process(productId, timestamp) // should NOT compile

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

Ответы [ 5 ]

3 голосов
/ 22 ноября 2010

Почему бы не использовать псевдонимы типов вместо этого? Я ценю, что они не идеальны (то есть они не решают вашу проблему компиляции), но они могут сделать ваш код более понятным без потери производительности?

type Timestamp = Long
type ProductId = Long

Затем вы можете написать методы, которые используют шаблон pimp my library и позволяют JVM использовать escape-анализ для устранения накладных расходов времени выполнения:

class RichTimestamp(self: Timestamp) {
  //whatever you want here
}

Обратите внимание, что применяются все обычные предостережения: если вы не очень уверены (поскольку вы, например, занимаетесь программированием со сверхнизкой задержкой), снижение производительности при использовании штучного типа, вероятно, не является проблемой. Я имею дело с системами, обрабатывающими десятки миллионов входов в день без каких-либо проблем!

2 голосов
/ 21 ноября 2010

Корень иерархии типов Scala Any с дочерними элементами AnyVal и Anyref.Все целочисленные типы (например, Long в вашем примере) происходят от AnyVal, и вы не можете создавать подклассы на этой стороне дерева.Дочерние элементы AnyVal представляют типы низкого уровня в JVM.Стирание типа означает, что во время выполнения действительно нет AnyVal, и если бы вы могли сделать Timestamp, оно также было бы потеряно во время выполнения.Для хранения информации о типе оболочки вам нужен бокс / распаковка.

case class Timestamp(ts: Long)

Хорошая JVM может устранить большую часть накладных расходов по упаковке / распаковке во время выполнения.Например, см. Опыт с включенным анализом побега на JVM

1 голос
/ 22 ноября 2010

Подобные вещи могут быть обеспечены плагином.Плагин неподдерживаемых и нерабочих модулей для Scala, в конце концов, делал что-то подобное, когда он предотвращал добавление расстояний к длительностям.

1 голос
/ 22 ноября 2010

Концепция примитивов ( в JVM ) заключается в том, что они предопределены и являются окончательными, вы не можете добавить дополнительные примитивы в JVM, только классы (java.lang.Object в Java или scala.AnyRef в Scala) ...

Упаковка / распаковка обертки, предложенная Беном case class Timestamp(ts: Long), не должна создавать значительную производительность.

псевдонимы типов, type Timestamp = Long, на самом деле псевдонимы , поэтому компилятор не может различить два псевдонима одного и того же типа (Long).

0 голосов
/ 20 июля 2018

Это теперь возможно, начиная с 2.10, с значениями классов .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...