Strongly typed identifier

A UML class diagram for a strongly typed identifier.
A UML class diagram for a strongly typed identifier.

A strongly typed identifier is user-defined data type which serves as an identifier or key that is strongly typed. This is a solution to the "primitive obsession" code smell as mentioned by Martin Fowler. The data type should preferably be immutable if possible. It is common for implementations to handle equality testing, serialization and model binding.

The strongly typed identifier commonly wraps the data type used as the primary key in the database, such as a string, an integer or universally unique identifier (UUID).

Web frameworks can often be configured to model bind properties on view models that are strongly typed identifiers. Object–relational mappers can often be configured with value converters to map data between the properties on a model using strongly typed identifier data types and database columns.

Examples

Passing a strongly typed identifier throughout the layers of an example application.

Passing a strongly typed identifier throughout the layers of an example application

C#

C# have records which provide immutability and equality testing.[1] The record is sealed to prevent inheritance.[2] It overrides the built-in ToString() method.[3]

This example implementation includes a static method which can be used to initialize a new instance with a randomly generated globally unique identifier (GUID).

/// <summary>
/// Represents a user identifier.
/// </summary>
/// <param name="Id">The user identifier.</param>
public sealed record UserId(Guid Id)
{
    /// <summary>
    /// Initializes a new instance of the <see cref="UserId" /> record.
    /// </summary>
    /// <returns>A new UserId object.</returns>
    public static UserId New() => new(Guid.NewGuid());

    public override string ToString() => Id.ToString();
}

C++

C++ have structs but not immutability so here the id field is marked as private with a method named value() to get the value.

struct UserId {
    UserId(const string _id)
    {
        id = _id;
    }

    string value() const
    {
        return id;
    }

    bool operator==(const UserId& rhs) const
    {
        return value() == rhs.value();
    }

private:
    string id;
};

ostream& operator << (ostream &os, const UserId &id)
{
    return os << id.value() << std::endl;
}

Crystal

Crystal's standard library provides the record macro for creating records which are immutable structs and lets you create override the built-in to_s method.[4]

require "uuid"

# Represents a user identifier.
record UserId, id : String do
  def initialize()
    @id = UUID.v4.to_s
  end

  def to_s(io)
    io << id
  end

  def self.empty
    self.new(UUID.empty.to_s)
  end
end

D

D have immutable structs.[5]

import std;

/** Represents a user identifier. */
immutable struct UserId
{
    immutable UUID id;

    /** Initializes a new instance of the UserId struct. */
    this(immutable string id)
    {
        this.id = UUID(id);
    }

    public static UserId create()
    {
        return UserId(randomUUID.toString());
    }

    string toString()
    {
        return this.id.toString();
    }
}

Dart

Dart have classes with operator overloading.

import 'package:meta/meta.dart';

/// Represents a user identifier.
@immutable
final class UserId {
  final String id;

  /// Initializes a new instance of the UserId struct.
  const UserId(this.id);

  @override
  operator ==(other) => other is UserId && other.id == id;
  @override
  int get hashCode => id.hashCode;
  @override
  String toString() => id;
}

F#

F# lets you create override the Equals, GetHashCode and ToString methods.

open System

/// <summary>
/// Represents a user identifier.
/// </summary>
/// <param name="id">The user identifier.</param>
type UserId(id: Guid) =
    member x.id = id
    static member New() = Guid.NewGuid()
    static member Empty = Guid.Empty
    override x.Equals(b) =
      match b with
      | :? UserId as p -> id = p.id
      | _ -> false
    override x.GetHashCode() = hash id
    override x.ToString() = id.ToString()

Go

Go have structs which provide equality testing. Go however does not provide immutability.

// Represents a user identifier.
type UserId struct{ id string }

// Creates a new user identifier.
func NewUserId(id string) UserId { return UserId{id: id} }

func (x UserId) String() string { return x.id }

Groovy

Groovy have record classes which provide immutability and equality testing.[6]

/**
 * Represents a user identifier.
 *
 * @param id The user identifier.
 */
record UserId(String id) {
    String toString() { id }
}

Haskell

Haskell can create user-defined custom data types using the newtype keyword.[7] It provides equality testing using the Eq standard class and printing using the Read and Show standard classes.

-- Represents a user identifier.
newtype UserId = UserId String deriving (Eq, Read, Show)

Java

Java have records which provide equality testing.[8] The record is declared using the final modifier keyword to prevent inheritance. It overrides the built-in toString() method.

import java.util.UUID;

/**
 * Represents a user identifier.
 * @param id The user identifier.
 */
public final record UserId(UUID id) {
    /**
     * Initializes a new instance of the UserId record.
     * @return A new UserId object.
     */
    public static UserId newId() {
        return new UserId(UUID.randomUUID());
    }

    public String toString() {
        return id.toString();
    }
}

JavaScript

This JavaScript example implementation provides the toJSON method used by the JSON.stringify()[9] function to serialize the class into a simple string instead of a composite data type. It calls Object.freeze() to make the instance immutable.[10] It overrides the built-in toString() method[11] and the valueOf() method.[12]

class UserId {
  #id;

  constructor(id) {
    if (id == undefined) {
      throw new TypeError("Argument is null or undefined.");
    }
    this.#id = id;
    Object.freeze(this);
  }

  static empty = new this.prototype.constructor("00000000-0000-0000-0000-000000000000");

  static new() {
    return new this.prototype.constructor(crypto.randomUUID());
  }

  equals(id) {
    return id instanceof this.constructor && this.#id === id.valueOf();
  }

  toJSON() {
  	return this.#id;
  }

  toString() {
    return this.#id;
  }

  valueOf() {
  	return this.#id;
  }
}

Julia

Julia have immutable composite data types.[13]

using UUIDs

"Represents a user identifier."
struct UserId
    id::UUID
end

Base.string(userId::UserId) = userId.id

Kotlin

Kotlin have "inline classes".[14]

/**
 * Represents a user identifier.
 *
 * @property id The user identifier.
 * @constructor Creates a user identifier.
 */
@JvmInline
public value class UserId(public val id: String) {
    override fun toString() = id
}

Nim

Nim have "distinct types".[15][16]

## Represents a user identifier.
type UserId* = distinct string

PHP

This PHP example implementation implements the __toString() magic method.[17] Furthermore, it implements the JsonSerializable interface which is used by the built-in json_encode function to serialize the class into a simple string instead of a composite data type.[18] The class is declared using the final modifier keyword to prevent inheritance.[19] PHP has traits as a way to re-use code.[20]

/**
 * Represents a user identifier.
 */
final class UserId implements JsonSerializable
{
    use StronglyTypedIdentifier;
}

/**
 * Provides methods for use with strongly typed identifiers.
 */
trait StronglyTypedIdentifier
{
    /**
     * Initializes a new instance of the UserId object.
     * @param string $id The user identifier.
     */
    public function __construct(public readonly string $id) {}

    /**
     * Creates a new user identifier.
     */
    public static function new(): self
    {
        return new self(bin2hex(random_bytes(16)));
    }

    public function jsonSerialize(): string
    {
        return $this->id;
    }

    public function __toString(): string
    {
        return $this->id;
    }
}

Python

Python has data classes which provides equality testing and can be made immutable using the frozen parameter.[21] It overrides the __str__ dunder method.[22]

This example implementation includes a static method which can be used to initialize a new instance with a randomly generated universally unique identifier (UUID).

from dataclasses import dataclass
import uuid

@dataclass(frozen=True)
class UserId:
    """Represents a user identifier."""

    id: uuid.UUID

    @staticmethod
    def new() -> Self:
        """Create a new user identifier."""
        return __class__(uuid.uuid4())

    def __str__(self):
        return str(self.id)

Python also has NewType which can be used to create new data types.[23]

from typing import NewType

UserId = NewType('UserId', int)

Ruby

Ruby have data classes which provides equality testing and are immutable.[24] It overrides the built-in to_s method.

This example implementation includes a static method which can be used to initialize a new instance with a randomly generated universally unique identifier (UUID).

require 'securerandom'

# Represents a user identifier.
UserId = Data.define(:id) do
  # Create a new user identifier.
  def self.create
    self.new(SecureRandom.uuid)
  end

  def self.empty
    self.new('00000000-0000-0000-0000-000000000000')
  end

  def to_s
    id
  end
end

Rust

In Rust this can be done using a tuple struct containing a single value.[25] This example implementation implements the Debug[26] and the PartialEq[27] traits. The PartialEq trait provides equality testing.

// Represents a user identifier.
#[derive(Debug, PartialEq)]
pub struct UserId(String);

Scala

Scala have case classes which provide immutability and equality testing.[28] The case class is sealed to prevent inheritance.

import java.util.UUID

/** Represents a user identifier.
  *
  * @constructor
  *   Create a new user identifier.
  * @param id
  *   The user identifier.
  */
sealed case class UserId(id: UUID)

object UserId:
  /** Initializes a new instance of the UserId class. */
  def create(): UserId = UserId(UUID.randomUUID())

Swift

Swift have the CustomStringConvertible protocol which can be used to provide its own representation to be used when converting an instance to a string,[29] and the Equatable protocol which provides equality testing.[30]

import Foundation

/// Represents a user identifier.
struct UserId: CustomStringConvertible, Equatable {
    private let id: UUID

    init(_ id: UUID) {
        self.id = id
    }

    var description: String {
        return id.uuidString.lowercased
    }

    /// Creates a new user identifier.
    static func new() -> Self {
        return Self(UUID())
    }
}

Zig

Zig have structs[31] with constants but by design does not have operator overloading[32] and method overriding.

/// Represents a user identifier.
const UserId = struct {
    value: i32,

    /// Initializes a new instance of the UserId struct.
    pub fn init(value: i32) UserId {
        return UserId{ .value = value };
    }
};

See also

References

  1. ^ "Records - C# reference". learn.microsoft.com. Retrieved 23 January 2023.
  2. ^ "sealed modifier - C# Reference". learn.microsoft.com. Retrieved 23 January 2023.
  3. ^ "Object.ToString Method (System)". learn.microsoft.com. Retrieved 14 June 2023.
  4. ^ "Structs - Crystal". crystal-lang.org. Retrieved 21 February 2024.
  5. ^ "Structs, Unions - D Programming Language". dlang.org. Retrieved 30 May 2023.
  6. ^ "The Apache Groovy programming language - Object orientation". groovy-lang.org. Retrieved 24 December 2023.
  7. ^ "Newtype - HaskellWiki". wiki.haskell.org. Retrieved 18 June 2023.
  8. ^ "Record Classes". Oracle Help Center. Retrieved 24 January 2023.
  9. ^ "JSON.stringify() - JavaScript | MDN". developer.mozilla.org. Retrieved 23 January 2023.
  10. ^ "Object.freeze() - JavaScript | MDN". developer.mozilla.org. Retrieved 23 January 2023.
  11. ^ "Object.prototype.toString() - JavaScript | MDN". developer.mozilla.org. Retrieved 23 January 2023.
  12. ^ "Object.prototype.valueOf() - JavaScript | MDN". developer.mozilla.org. Retrieved 23 January 2023.
  13. ^ "Types · The Julia Language". docs.julialang.org. Retrieved 30 May 2023.
  14. ^ "Inline classes | Kotlin". Kotlin Help. Retrieved 23 January 2023.
  15. ^ "Nim Manual". nim-lang.org. Retrieved 4 August 2023.
  16. ^ "Nim by Example - Distinct Types". nim-by-example.github.io. Retrieved 4 August 2023.
  17. ^ "PHP: Magic Methods - Manual". www.php.net. Retrieved 23 January 2023.
  18. ^ "PHP: JsonSerializable::jsonSerialize - Manual". www.php.net. Retrieved 23 January 2023.
  19. ^ "PHP: Final Keyword - Manual". www.php.net. Retrieved 23 January 2023.
  20. ^ "PHP: Traits - Manual". www.php.net. Retrieved 2 May 2023.
  21. ^ "dataclasses — Data Classes". Python documentation. Python Software Foundation. Retrieved 23 January 2023.
  22. ^ "3. Data model". Python documentation. Python Software Foundation. Retrieved 12 June 2023.
  23. ^ "typing — Support for type hints". Python documentation. Python Software Foundation. Retrieved 17 June 2023.
  24. ^ "class Data - Documentation for Ruby 3.3". docs.ruby-lang.org. Retrieved 6 February 2023.
  25. ^ "New Type Idiom - Rust By Example". doc.rust-lang.org. Retrieved 18 June 2023.
  26. ^ "Debug in std::fmt - Rust". doc.rust-lang.org. Retrieved 23 January 2023.
  27. ^ "PartialEq in std::cmp - Rust". doc.rust-lang.org. Retrieved 23 January 2023.
  28. ^ "Case Classes". Scala Documentation. Retrieved 15 May 2023.
  29. ^ "CustomStringConvertible". Apple Developer Documentation. Retrieved 5 May 2023.
  30. ^ "Documentation". docs.swift.org. Retrieved 4 May 2023.
  31. ^ "Structs | zig.guide". zig.guide. 20 April 2024. Retrieved 15 October 2024.
  32. ^ "Documentation - The Zig Programming Language". Retrieved 15 October 2024.

Read other articles:

Bryopsida Kapsul Arthrodontous dari Dicranella varia Klasifikasi ilmiah Kerajaan: Plantae Divisi: Bryophyta Kelas: Bryopsida(Limpr.) Rothm. Subkelas[1] Bryidae Buxbaumiidae Dicranidae Diphysciidae Funariidae Timmiidae Bryopsida merupakan kelas terbesar dari lumut daun (Musci), [2]yang terdiri dari hampir 95% spesies lumut daun. Terdapat sekitar 11,500 spesies yang tersebar di seluruh dunia. Klasifikasi Pada masa lalu, semua lumut daun masuk dalam grup Bryopsida, sebelum akhir...

 

Grand Prix Jepang 2012 Lomba ke-15 dari 20 dalam Formula Satu musim 2012 Detail perlombaanTanggal 7 October 2012Nama resmi 2012 Formula 1 Japanese Grand Prix[1]Lokasi Suzuka Circuit, Suzuka, Mie, JapanSirkuit Permanent racing facilityPanjang sirkuit 5.807 km (3.608 mi)Jarak tempuh 53 putaran, 307.471 km (191.062 mi)Cuaca Dry and sunnyPosisi polePembalap Sebastian Vettel Red Bull-RenaultWaktu 1:30.839Putaran tercepatPembalap Sebastian Vettel Red Bull-RenaultWaktu 1:35.774 putaran ke-52...

 

Artikel ini memiliki beberapa masalah. Tolong bantu memperbaikinya atau diskusikan masalah-masalah ini di halaman pembicaraannya. (Pelajari bagaimana dan kapan saat yang tepat untuk menghapus templat pesan ini) Artikel ini berisi daftar yang lebih baik ditulis dalam bentuk prosa. Anda dapat membantu Wikipedia dengan mengubah artikel ini ke dalam bentuk prosa, jika sesuai. (Maret 2021) Artikel ini membutuhkan rujukan tambahan agar kualitasnya dapat dipastikan. Mohon bantu kami mengembangkan ar...

Pression acoustique La pression acoustique est une mesure de l'ambiance sonore en un point, indépendante de la direction du signal.Données clés Unités SI pascal (Pa) Dimension M·L −1·T −2 Nature Grandeur scalaire intensive Symbole usuel P , p {\displaystyle P,p} Lien à d'autres grandeurs I → {\displaystyle {\overrightarrow {I}}} = p {\displaystyle p} . v → {\displaystyle {\overrightarrow {v}}} modifier La pression acoustique est la valeur efficace, sur ...

 

Halaman ini berisi artikel tentang sejarawan militer Australia. Untuk pejabat serikat dagang Inggris, lihat George Odger. George James OdgersCanberra, circa. 1954Lahir29 Maret 1916Perth, Australia BaratMeninggal2008KebangsaanAustraliaPekerjaanPrajurit, jurnalis dan sejarawanDikenal atasSejarawan militer George James Odgers (1916–2008) adalah seorang prajurit, jurnalis dan sejarawan militer asal Australia. Odgers bertugas dalam Australian Army sebagai prajurit privat dan perwira non-komisi; ...

 

Erik BreukinkErik Breukink lors de la 8e étape du Tour de France 2007InformationsNaissance 1er avril 1964 (60 ans)RhedenNationalité néerlandaiseDistinction Cycliste néerlandais de l'annéeÉquipes professionnelles 1985Skala-Gazelle1986Panasonic1987-1989Panasonic-Isostar1990-1992PDM-Concorde1993-1995ONCE1996-1997RabobankÉquipes dirigées 2004-2012Rabobank01.2015-03.2015[n 1]Roompot03.2015-12.2015[n 2]Roompot Oranje Peloton2016Roompot-Oranje Peloton2017-2019Roompot-Nederlandse Lo...

Liga Champions UEFA 2001–2002Hampden Park di Glasgow, Skotlandia mengadakan finalInformasi turnamenJadwalpenyelenggaraanKualifikasi:11 Juli – 8 September 2001Kompetisi utama:11 September 2001 – 15 Mei 2002Jumlahtim pesertaKompetisi utama: 32Total: 72Hasil turnamenJuara Real Madrid (gelar ke-9)Tempat kedua Bayer LeverkusenStatistik turnamenJumlahpertandingan157Jumlah gol393 (2,5 per pertandingan)Jumlahpenonton5.411.714 (34.470 per pertandingan)Pencetak golterbanyakRuud van Nist...

 

Roman legion Not to be confused with the various other Legiones II of the Roman Army. Second Legion AugustaLegio II AugustaLegio Secunda AugustaMap of the Roman empire in AD 125, under emperor Hadrian, showing the Legio II Augusta, stationed at Isca Silurum (Caerleon, Wales), in Britannia province, from AD 74 to at least 269Active43 BC to sometime in the 4th century ADCountryRoman Republic and Roman EmpireTypeRoman legion (Marian)RoleInfantry assault (some cavalry support)SizeVaried over unit...

 

World Boxing AssociationDisciplina Pugilato Fondazione1962 GiurisdizioneMondiale Sede Panama PresidenteGilberto Mendoza, Jr. MottoSimply the pioneers Sito ufficialewww.wbaboxing.com/ e www.wbaboxing.com/es Modifica dati su Wikidata · Manuale La World Boxing Association (WBA) è un'organizzazione di boxe che sancisce le gare ufficiali, e patrocina il campionato del mondo WBA, a livello professionistico. Nata nel 1921 a Rhode Island come NBA (National Boxing Association), con il compito d...

Heart of Darkness 'Heart of Darkness' pertama kali diterbitkan di Majalah Blackwood dalam tiga seri.PengarangJoseph ConradNegaraBritania RayaBahasaInggrisGenreFrame story, NovellaPenerbitBlackwood's MagazineTanggal terbitFebruari 1899Jenis mediaCetak (serial)ISBNISBN N/A Invalid ISBNDiikuti olehLord Jim (1900)  Heart of Darkness (1899) adalah novel pendek yang ditulis oleh penulis Polandia Joseph Conrad. Novel ini berkisah tentang kehidupan Charles Marlow sebagai...

 

Serbie-et-Monténégro au Concours Eurovision Pays  Serbie-et-Monténégro Radiodiffuseur RTS, RTCG Émission de présélection Evropesma Participations 1re participation Eurovision 2004 Participations 2 (en 2005) Meilleure place 2e (en 2004) Moins bonne place 7e (en 2005) Liens externes Page officielle du diffuseur Page sur Eurovision.tv modifier  La Serbie-et-Monténégro a participé à deux éditions du Concours Eurovision de la chanson, en 2004 et 2005, sans le remporter[1]. P...

 

New York has a long history of LGBT community building, activism, and culture which extends to the early history of the city. Timeline of events 1890s Manhattan's Bowery was known to host fairy resorts, saloons or dance halls for male gays, (known as fairies at the time). These 'resorts' included the venues: Paresis Hall, Little Bucks, Manilla Hall, the Palm Club of Chrystie Street, the Black Rabbit at 183 Bleecker Street, and The Slide at 157 Bleecker Street were the site of many gay and dr...

West Hartford redirects here. For the unincorporated community in Missouri, see West Hartford, Missouri. For the community in Vermont, see West Hartford, Vermont. Town in Connecticut, United StatesWest Hartford, ConnecticutTownTown of West HartfordBlue Back Square SealLogoNickname: WeHaMotto: Where City Style Meets Village Charm Hartford County and Connecticut Capitol Planning Region and ConnecticutShow West HartfordShow ConnecticutShow the United StatesCoordinates: 41°46...

 

Süper LigBadan yang mengaturFederasi Sepak Bola Turki (TFF)Negara TurkiKonfederasiUEFADibentuk21 Februari 1959; 65 tahun lalu (1959-02-21)Jumlah tim19 (20 di musim 2023–24)Tingkat pada piramida1Degradasi keTFF First LeaguePiala domestikPiala TurkiPiala Super TurkiPiala internasionalUEFA Champions LeagueUEFA Europa Conference LeagueJuara bertahan ligaGalatasaray (23 gelar) (2022–23)Klub tersuksesGalatasaray (23 gelar)Pencetak gol terbanyakHakan Şükür (249)[1]Televisi penyi...

 

Forum Demokratik Bangsa Jerman di Rumania bahasa Rumania: Forumul Democrat al Germanilor din RomâniaJerman: Demokratisches Forum der Deutschen in Rumäniencode: de is deprecated PresidenPaul-Jürgen PorrKetua di DPROvidiu GanțDibentuk28 Desember 1989 (28 Desember 1989) di Sighişoara/SchäßburgIdeologiKepentingan minoritas JermanKelompok Parlemen EropaEPP-ED (Januari-November, 2007)Warna  Merah-merah tedasSenat0 / 136DPR1 / 330Parlemen Eropa0 / 33Situs webwww.fdgr.ro Forum De...

British bicycle manufacturer Raleigh Bicycle CompanyCompany typePrivate company limited by sharesIndustryBicyclesPredecessorWoodhead and Angois (1885, later Woodhead, Angois and Ellis)FoundedDecember 1888; 135 years ago (1888-12), registered as a limited liability company in January 1889FoundersFrank Bowden, Richard Woodhead and Paul AngoisFateOwned by AccellHeadquartersEastwood, Nottinghamshire, United KingdomWebsiteraleigh.co.uk The Raleigh Bicycle Company is a Britis...

 

Prefecture of Japan JP-21 redirects here. For the Japanese RGB-21 connector, see SCART. Prefecture in Chūbu, JapanGifu Prefecture 岐阜県PrefectureJapanese transcription(s) • Japanese岐阜県 • RōmajiGifu-kenPanoramic view of the Nōbi Plain with Gifu City, Gifu Prefecture seen from the top of Gifu Castle FlagSymbolAnthem: Gifu kenmin no utaCountry JapanRegionChūbu (Tōkai)IslandHonshuCapitalGifuSubdivisionsDistricts: 9, Municipalities: 42Government...

 

Human settlement in EnglandArretonArreton Old VillageArretonLocation within the Isle of WightArea7.465 sq mi (19.33 km2) [1]Population988 (2011 Census including Blackwater , Downend , Horringford and Mereton)[2]• Density132/sq mi (51/km2)OS grid referenceSZ545865Civil parishArretonUnitary authorityIsle of WightCeremonial countyIsle of WightRegionSouth EastCountryEnglandSovereign stateUnited KingdomPost townNEWPORTP...

Italian novelist, dramatist, poet and screenwriter You can help expand this article with text translated from the corresponding article in Italian. (July 2018) Click [show] for important translation instructions. Machine translation, like DeepL or Google Translate, is a useful starting point for translations, but translators must revise errors as necessary and confirm that the translation is accurate, rather than simply copy-pasting machine-translated text into the English Wikipedia. Do ...

 

安哥拉经济货币安哥拉寬扎 (AOA)财政年度歷年贸易组织非洲联盟, 世界貿易組織统计数据GDP$1149.5億美元(2008[update]年)GDP增长率13.2%[1]人均GDP$8,800 (2008[update]年)各产业GDP農業(9.2%),工業(65.8%),服務業(24.6%) (2008[update]年)[1]通货膨胀(CPI)12.5% (2008[update]年)[1]贫困人口40.5% (2006[update]年估計值)[1]劳动力776.9萬 (2009[...