Тегированный тип против класса расширяет AnyVal

Чтобы повысить безопасность типов, мы можем либо использовать тегированный тип, предоставляемый shapeless, либо создать класс, который расширяет AnyVal. Каковы различия и преимущества/недостатки использования одного над другим?

Пример:

trait CountryCodeTag
type CountryCode = String @@ CountryCodeTag

class CountryCode(code: String) extends AnyVal

person gyoho    schedule 14.10.2017    source источник


Ответы (2)


type CountryCode = String @@ CountryCodeTag

String @@ CountryCodeTag является подтипом String, т.е. все методы из String можно использовать напрямую: countryCode.toUpperCase.

String @@ CountryCodeTag можно случайно использовать там, где ожидается некоторое String, т.е. это менее безопасно для типов.

Создавать новые значения немного неудобно: "a".asInstanceOf[String @@ CountryCodeTag] или val tagger = new Tagger[CountryCodeTag]; tagger("a").

Зависимость от Shapeless (хотя это можно сделать вручную).

class CountryCode(code: String) extends AnyVal

Это более безопасно для типов.

Методы из String доступны с некоторыми дополнительными усилиями:

class CountryCode(val code: String) extends AnyVal
new CountryCode(countryCode.code.toUpperCase)

or

class CountryCode(val code: String) extends AnyVal 
object CountryCode {
  def unapply(...) = ...
}
countryCode match { case CountryCode(code) => new CountryCode(code.toUpperCase) }

or

case class CountryCode(code: String) extends AnyVal
countryCode.copy(code = countryCode.code.toUpperCase)

Создание новых значений немного более естественно: new CountryCode("a").

Никаких лишних зависимостей (это обычный Scala).

person Dmytro Mitin    schedule 14.10.2017
comment
Не могли бы вы привести пример недостатка: String @@ CountryCodeTag can be accidentally used where some String is expected? - person gyoho; 15.10.2017
comment
@gyoho val countryCode: String @@ CountryCodeTag = ??? case class Person(name: String) Person(countryCode) - person Dmytro Mitin; 15.10.2017
comment
С точки зрения объема памяти, какой из них, по вашему мнению, работает лучше? - person gyoho; 15.10.2017
comment
Во время выполнения оба CountryCode являются просто String (с методами извлекается в объект-компаньон), так что, думаю, разницы быть не должно. - person Dmytro Mitin; 15.10.2017
comment
@gyoho обратите внимание, что во многих случаях необходимо создать экземпляр класса anyval, что приводит к потере его преимуществ во время выполнения. - person puhlen; 15.10.2017

Эти два метода также имеют разные характеристики производительности.

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

https://failex.blogspot.nl/2017/04/the-high-cost-of-anyval-subclasses.html

person fusion    schedule 02.04.2018