Skip to content

Units of Measure

A breadth-first survey of units of measure — the mathematics of physical quantities and dimensional analysis (quantity calculus, the Buckingham π theorem, free abelian groups of dimensions, tensor lines, torsors, dimensioned algebra, and Kennedy's type-theoretic line), and the twenty checked-units systems real ecosystems ship, from compiler-native (F#, GNAT) through static library encodings (Rust, C++, Haskell, D) and dependent types (Lean) to dispatch-time (Julia), runtime registries (Python), and symbolic engines (Wolfram / MATLAB). The goal is a grounded map of the design space to inform a future Sparkles quantities library: the repo's constraints — templates + CTFE, @safe pure nothrow @nogc cores, Expected-based error handling — select a specific region of that space, and the survey closes with the delta (comparison, Part IV), the D prior art (d-quantities), and thirteen CI-verified runnable D prototypes (examples/).

This survey answers seven questions:

  1. What is a quantity — and what, exactly, is wrong with 1 m + 1 s? The metrology vocabulary (VIM, SI Brochure, UCUM, QUDT) and the six-account orientation ledger for the survey's central prohibition. See concepts.
  2. What are the classical results? The π-theorem as rank–nullity over the dimension matrix — with the hypotheses folklore elides — and the free-abelian-group skeleton every library implements. See buckingham-pi and free-abelian-group.
  3. What are the rigorous formalizations of "quantity"? Whitney's rays and birays, Tao's tensor of lines, the torsor/weight-space picture, and Hart's dimensioned linear algebra — with what each takes as primitive. See the theory subtree.
  4. How does the algebra become a type system? Kennedy's line — types-as-invariance, AG-unification, erasure — and the six mechanism families that encode the group in real checkers. See kennedy-types and type-system-mechanisms.
  5. How do real ecosystems package this? Twenty systems, from the one compiler with the theory built in to registries and symbolic engines. See the master catalog.
  6. What does the field agree on, and where does it split? Seven consensus points, nine genuinely open trade-off axes, and a candidate unifying hypothesis (quantities as a graded object) tested against the evidence. See the comparison.
  7. Where would a Sparkles units library sit? The D evidence — two complete prior designs, thirteen runnable prototypes — and the open decisions a docs/specs/ proposal must make. See comparison, Part IV, d-quantities, and the prototypes.

NOTE

Scope: foundations, vocabulary, and twenty flagship systems (waves 1–2). The theory subtree (eight deep-dives), the concepts glossary, the twenty system pages below, the comparison capstone, and the three CI-verified D prototypes are landed. Wave 2 has now landed six further system pages — the Scala libraries (coulomb + squants), Nim's unchained, Swift's Foundation Measurement, Kotlin's measured, and the UCUM / QUDT interchange implementations — taking the catalog from fourteen to twenty systems. Several systems are covered as in-page asides rather than own rows: astropy.units (inside python-pint), Eisenberg's units package (inside haskell-dimensional), std::chrono (inside cpp-boost-units), nordlow/units-d (inside d-quantities), NeedleInAJayStack/Units (inside swift-units), and the JSR-385 indriya / unit-api layer (inside ucum-qudt). Other-language units libraries remain out of scope for now; the UCUM spec and the QUDT ontology themselves are covered in concepts as the interchange and data poles of the design space.

Last reviewed: July 4, 2026


Foundations (theory)

The formalizations, each developed in its own deep-dive. Start with the concepts glossary for the shared vocabulary, then the theory umbrella for the organizing question (what is wrong with 1 m + 1 s, and what is primitive) and the cross-cutting splits.

TopicWhat it pins downCanonical sourcesLink
Concepts & vocabularyVIM/SI/UCUM/QUDT definitions; the one-prohibition-six-accounts ledger; the affine/logarithmic/angle edge casesVIM 3rd ed.; SI Brochure 9th ed.; NIST SP 811; UCUM; QUDTconcepts
Buckingham π via linear algebrathe π-theorem as rank–nullity over + one analytic step; the hidden-hypotheses ledgerVaschy 1892; Buckingham 1914; Bridgman 1922; Drobot 1953; CLP 1982pi
Whitney's quantity structuresquantities-first axiomatics; the Q ≅ ℝ × ℚⁿ representation theorem; the unresolved exponent ringWhitney 1968 (Monthly I & II); Raposo 2018/2019; Jonsson 2021whitney
Free abelian groupdimensions as exponent vectors (ℤⁿ/ℚⁿ); two GL-actions; what ℤ → ℚ buys and breaksKennedy 1996; Jonsson 2020/2021; Zapata-Carratalá 2021; the Lean repofag
Tensor of linesbase dimensions as 1-D lines; units as basis vectors; inconsistency as unwritabilityTao 2012; Janyška–Modugno–Vitolo 2007tensor
Torsor / scaling torushomogeneity = equivariance under (ℝ⁺)ⁿ; units = torsor points; trivialization never canonicalBaez; Tao 2012; Zapata-Carratalá 2021; Jonsson 2021torsor
Kennedy's typesprincipal types via unitary AG-unification; parametricity = invariance under rescaling; erasureWand & O'Keefe 1991; Kennedy 1994/1996/1997/2010kennedy
Hart's multidimensional analysisdimensioned linear algebra: multipliable ⇔ dimensionally rank-1; most of matrix theory breaksHart 1994 (SIAM) & 1995 (Springer); Zapata-Carratalá 2021hart
Type-system mechanismsthe theory→systems bridge: six encodings of the group; the checker evaluates vs solvesKennedy 2010; Gundry 2015; the pinned system source treesmech

Systems master catalog

One row per surveyed system — the identity and classification columns only. Checked is when a mismatch is reported: at compile time, at elaboration (proof assistant), per JIT dispatch specialization, at run time, or only on an explicit opt-in query. Exponents is the dimension group's exponent domain as shipped. Kind is whether same-dimension, different-kind quantities (Hz vs Bq, torque vs energy) are distinguishable. The full per-dimension comparison — affine and logarithmic support, polymorphism, erasure evidence, diagnostics, compile cost — is the comparison's at-a-glance matrix; this catalog is who-is-who.

SystemEcosystemMechanismCheckedExponentsKindLink
F# units of measureF# / .NETnative AG unifier in the compiler's constraint solvercompile¹—²fsharp-uom
uom-pluginHaskell (GHC)typechecker-plugin AG unifier over an uninterpreted Unit kindcompile³haskell-uom-plugin
dimensionalHaskellclosed type families over a fixed 7-slot Dimension kindcompileℤ⁷, closed basis—⁴haskell-dimensional
uomRustmacro-generated Quantity over typenum trait arithmeticcompileℤ⁷flat Kind tags⁵rust-uom
dimensionedRustmake_units! systems over typenum tarr! exponent arrayscompileℤⁿ per system⁶rust-dimensioned
mp-unitsC++20/23consteval symbolic expressions (constexpr values of empty types)compile, open basisquantity_spec hierarchy⁷cpp-mp-units
Boost.UnitsC++03MPL typelists of (base dimension, static_rational) pairscompile, open basisextra base dimensions⁸cpp-boost-units
AuC++14canonicalized variadic packs + a prime/π magnitude vector spacecompile, open basis—⁹cpp-au
quantities / std.unitsDCTFE dimension values · units-as-types conversion graphcompile¹⁰ (all artifacts)d-quantities
PintPythonruntime UnitRegistry + exponent dictionariesrun, open basispython-pint
Unitful.jlJuliaRational{Int} exponents as type parameters, multiple dispatchdispatch¹¹, open basisjulia-unitful
GNAT dimensionalityAda (GNAT-only)implementation-defined aspects; vectors on AST nodescompile, ≤ 7 dimensionsada-gnat-dimensions
LeanDimensionalAnalysisLean 4dependent types; CommGroup (dimension B E) proved, not encodedelaborationopen ring¹²lean-mathlib-units
Wolfram / MATLABWolfram Lang. · MATLABsymbolic Quantity data · inert symunit factorsrun / opt-in¹³ observedtemperature only¹⁴wolfram-matlab
coulombScalaopaque-type Quantity[V,U]=V + reflective-macro canonicalization (cansig)compile—¹⁵scala-coulomb
squantsScalaruntime values; a dimension is a distinct final class; F-bounded nominal typingcompile¹⁶n/a (nominal)nominal (free)¹⁷scala-squants
unchainedNimcompile-time-only macros over an integer QuantityPower arraycompilenim-unchained
measuredKotlinMeasure<T:Units> with nested UnitsProduct/UnitsRatio generics (no normalization)compile (structural)¹⁸kotlin-measured
Foundation MeasurementSwiftnominal Measurement<UnitType:Unit>; per-quantity Dimension subclasscompile¹⁹n/a (nominal)nominalswift-units
UCUM / QUDTJVM · JSUCUM string-grammar canonicalization / QUDT dimension-vector IRI; JSR-385 type-APIrun (7–8-slot)ucum-qudt

¹ Surface syntax defaults to integers, but parenthesized kg^(1/2) parses and the shipped solver is rational throughout — diverging from Kennedy's published design. ² 5.0<Hz> + 3.0<Bq> type-checks; the stdlib's own SI.fs defines both as second^-1. ³ Solver-side ; the surface ^: family takes only Nat (negative powers via /:, fractional powers inexpressible). Final release 0.4.0.0 (2022); GHC 9.0–9.4 only. ⁴ DTorque = DEnergy and DActivity = DFrequency are type synonyms by construction. ⁵ Kinds separate Hz/Bq, torque/energy, and temperature point/interval, but reset to the default kind under ×/÷ — comparability tags, not algebra. ⁶ Gaussian half-integer dimensions handled by rescaling the basis (SqrtCentimeter); dormant since 2022. ⁷ The field's most developed kind system: lowest-common-ancestor addition, a four-level conversion lattice, kind algebra closed under */÷. ⁸ Nine-base-unit SI (radian, steradian) makes torque ≠ energy, but Bq = Hz survives. ⁹ Explicit policy ("No plans at present to support"); Angle/Information ship as extra base dimensions instead. ¹⁰ Plus a run-time twin: quantities' QVariant throws DimensionException (GC + exceptions); all three D artifacts are dormant. ¹¹ Resolved per JIT specialization: a mismatch compiles to an unconditional throw, a match to bare arithmetic — a third category between compile and run. ¹² Any CommRing E exponents type-check; the artifact is theorems (noncomputable), not executables. ¹³ Wolfram checks eagerly at evaluation ($Failed on incompatibles); MATLAB checks only on an explicit checkUnits query returning logicals, never raising. ¹⁴ Wolfram curates DegreesCelsius vs DegreesCelsiusDifference; MATLAB defaults all temperatures to differences. ¹⁵ coulomb has NO Kind mechanism — torque/energy, Hz/Bq, angle/ratio are unguarded (the sharpest contrast with uom's Kind). ¹⁶ squants rejects Power + Energy at compile time as an ordinary nominal type mismatch; value + scale-conversion are runtime. ¹⁷ nominal typing gives kind-vs-dimension for free — TorqueEnergy despite identical dimension. ¹⁸ Kotlin has no type-level integers; composite dimensions are nested generic types (A·BB·A), not a normalized exponent vector; no fractional powers. ¹⁹ Foundation catches m + s as a generic-parameter mismatch, but there is no product type (m·s is unnameable); the typed third-party contrast on the same page (NeedleInAJayStack/Units) is runtime-thrown — neither is a full type-level exponent algebra.

Runnable prototypes

Thirteen single-file D programs co-located with this tree, compiled and run by the repository's ci helper on every pass; each header cross-links the theory or system page it demonstrates. The first three are zero-dependency and pin the core mechanism:

  • quantity-zn-graded.d — a minimal ℤ³-graded Quantity: the dimension is its unique normal form as a template value parameter; metres + seconds is a checked rejection via static assert(!__traits(compiles, …)).
  • quantity-rational-exponents.d — the ℚⁿ variant: CTFE-gcd-normalized rational exponents make sqrt total (sqrt(m²) is the length type) while m^(1/2) + m stays rejected.
  • quantity-erasure.d — representation-level erasure machine-checked (sizeof/alignof/offsetof/array layout), with the codegen-identity honesty boundary stated.

Ten more are motivated by a physically-based raytracer and, where relevant, composed with sparkles:math's Vector; they prototype the remaining design-space axes:

  • quantity-affine-torsor.d — affine Point3 vs Displacement vs Direction and Ray.at(Length t); Point + Point and scalar · Point rejected (composition ordering A: Quantity!(dim, Vec3) over the real Vector).
  • quantity-kind-tags.d — a flat Kind tag orthogonal to the exponent vector (HzBq, plane-angle ≠ ratio); kind erased under ×/÷.
  • quantity-nominal.d — a distinct struct per quantity (kind for free), hand-wired products, undeclared product unnameable; poor Vector reuse shown.
  • quantity-runtime-expected.d — a runtime dimension value; fallible ops return an Expected (m + s is a runtime err, not a throw).
  • quantity-unit-in-type.d — the unit (rational scale) lives in the type; nm + m converts lazily at the boundary, not eagerly at construction.
  • quantity-diagnostics.d — a CTFE pretty-printer emits domain-language static assert prose, contrasted with the raw mangled encoding.
  • quantity-polymorphism.d — dimension-aware generic dot/cross/ magnitude/normalize; forward IFTI inference works, the invert-from-result ceiling does not.
  • quantity-open-basis.d — an open (name, exp) dimension basis; mint a custom base dimension without editing a closed vector core.
  • quantity-logarithmic.d — EV/stops and dB: log-domain add = linear-domain multiply; why logarithmic units resist the exponent-vector model.
  • quantity-vector-composition.d — units ⋈ linear algebra, head to head: Vector!(Quantity, N) is blocked today (the isNumeric!T constraint) while an element-generic Vec works, yielding a co-design recommendation for sparkles:math (see the comparison capstone).

Taxonomy

By checking time

The survey's most load-bearing axis (comparison reads the matrix along it): when is a dimensional mismatch reported, and by whom.

Checking timeThe contractSystems
Compile — compiler-nativethe language's own type checker / semantic pass reports the mismatchF# (AG unifier), GNAT (sem_dim aspects)
Compile — compiler plugina plugin extends the stock solver with the abelian-group theoryuom-plugin
Compile — library encodingthe host's generic-programming machinery evaluates the group; no solverdimensional, uom, dimensioned, mp-units, Boost.Units, Au, D artifacts, coulomb, squants, unchained, measured, Foundation Measurement
Elaboration (proof assistant)homogeneity is a proposition; the output is theorems, not executablesLean
Dispatch / specializationthe check resolves per JIT specialization — mismatch compiles to a throwUnitful.jl
Runchecked when two quantities actually meet (registry / symbolic evaluation)Pint, Wolfram, UCUM / QUDT
Opt-in queryarithmetic never checks; an explicit call reports a logical verdictMATLAB symunit

By exponent domain

Theory published ; practice shipped (comparison § exponents); the free-abelian-group page tallies what the extension costs.

Exponent domainSystemsThe documented cost / benefit
— closed 7-vectordimensional, UCUM / QUDT (7–8-slot)sqrt of a non-square dimension is a compile error ("fractional powers make little physical sense")
— per-system vectorsuom, dimensioned, uom-plugin, unchained, measured (structural)Length.sqrt() rejected; √Hz named future work; Gaussian basis rescaled to stay integral
— capped basisGNAT (≤ 7 dimensions)Sqrt halves vectors; ** requires a static exponent
— open basisF#, mp-units, Boost.Units, Au, D, Pint, Unitful, coulombtotal sqrt and honest √Hz — at the price of freeness, perfect squares, and gcd structure
Open ringLeanany CommRing E; nothing enforces the physics convention against
observed (uncommitted)Wolfram / MATLABcaptures show integer powers only, with no stated bound
Nominal — no exponent vectorsquants, Foundation Measurementa dimension is a class / generic-parameter identity, not an exponent tuple — there is no domain to have

By kind treatment

The four-rung ladder from comparison § kinds — no rung is derived from theory, and QUDT (kind above dimension, as data) sits off-ladder.

RungMechanismSystems
1 — nothingthe dimension vector is the whole identity; Hz + Bq passesF#, GNAT, dimensional, dimensioned, uom-plugin, Pint, Unitful, Lean, D artifacts, coulomb, unchained, measured, UCUM / QUDT
2 — extra base dimensionsmint an axis; splits torque/energy but never Hz/BqBoost.Units (radian/steradian), Au (Angle, Information), Wolfram (angle/solid-angle/information/money/person axes)
3 — flat tagsnominal comparability tags, erased under ×/÷uom
4 — propagating hierarchya quantity_spec tree: LCA addition + a conversion latticemp-units
Nominal — kind for freesame-dimension quantities are distinct nominal types, so TorqueEnergy with no tag (off-ladder)squants, Foundation Measurement

Milestones

A timeline interleaving theory / formalization milestones with system / tooling milestones. Every date below is grounded in a landed page of this tree (per-result provenance in each page's Sources); uncertain entries are marked *.

YearTheory / formalization milestoneSystem / tooling milestone
1892Vaschy states the π-theorem (buckingham-pi)
1914Buckingham names it, proving "for special cases" under a sum-of-monomials postulate
1922BridgmanDimensional Analysis: complete equations, the tacit single-relation restriction
1953Drobot — the first fully rigorous algebraic foundation
1968WhitneyThe Mathematics of Physical Quantities I & II (whitney)
1982Curtis–Logan–Parker — the π-theorem as frames + group action, no smoothness
1991Wand & O'Keefe — dimensional inference "fits neatly" into ML type inference
1994KennedyDimension Types (ESOP); Hart — dimensioned matrices (SIAM)ML Kit extension — the first implementation of Kennedy's dimension types (kennedy-types)
1995–1997Kennedy's thesis (TR-391, 1996) and POPL '97 parametricity; Hart's Springer book (1995)
2003Schabel's MPL dimensional-analysis demo — Boost.Units' origin (cpp-boost-units)
2007Janyška–Modugno–Vitolo — positive spaces (arXiv, Oct)Boost.Units formal review (Feb; after a factor-of-10 compile-time rewrite)
2008Boost.Units 1.0.0 ships in Boost 1.36 (Aug), exponents from the start
2010Kennedy's CEFP notes — the shipped F# design, didactically (kennedy-types)Boost.Units feature-frozen (v1.2, Boost 1.43)
2011Nadlinger's std.units Phobos RFC (Apr) and push (Dec) — never formally reviewed (d-quantities)
2012Tao — the tensor-of-lines / weight-space essay (Dec) (tensor-of-lines)GNAT dimensionality aspects presented (HILT 2012*); Mathematica 9.0 ships Quantity (wolfram-matlab)
2013quantities — D's CTFE value-level design (Sicard, 2013–2020) (d-quantities)
2014Atkey — parametricity → conservation laws, closing Kennedy's POPL '97 conjecture
2015Gundry — the GHC typechecker-plugin AG unifier (haskell-uom-plugin)dimensioned 0.5.0 moves to typenum (Dec) (rust-dimensioned)
2016units-d fork created the day the std.units thread ends (30 Mar) (d-quantities); Foundation Measurement ships with Swift 3* (swift-units)
2017–2018MATLAB symunit/checkUnits (R2017a); unitConvert (R2018b)
2018–2019Raposo — the algebraic structure of quantity calculus, I & II (whitney)
2020–2021Jonsson (2020 π-foundation; 2021 scalable monoids); Zapata-Carratalá — dimensioned algebramp-units P1935R2 before WG21 (2020) (cpp-mp-units); squants v1.8.3 — last tagged release (Aug 2021) (scala-squants)
2022uom-plugin 0.4.0.0 final (Oct; GHC 9.0–9.4, then dormant); dimensioned 0.8.0 final (Apr)
2023P2980R1 — the C++29 standardization plan; JSR-385 unit-api v2.2 (May) (ucum-qudt)
2025Bobbin et al. — the Lean 4 formalization (arXiv, Sep) (lean-mathlib-units)mp-units v2.5.0 (Dec); coulomb v0.9.1 (Sep) (scala-coulomb)
2026*P3045R8Quantities and units library (WG21); Kotlin measured v0.5.0 (Apr) (kotlin-measured); indriya v2.2.4, the JSR-385 RI (May) (ucum-qudt); current pins as reviewed: uom 0.38.0, Unitful 1.28.0, Pint 0.25.3

* The HILT 2012 attribution (Pucci & Schonberg) is stated on the GNAT page but has no local artifact behind it; the Swift 3 / macOS 10.12 date for Foundation Measurement is the platform era, not a pinned release; 2026 entries are current-as-of-review (July 2026).


Quick navigation

Suggested reading paths

Synthesis

  • Concepts & vocabulary — the metrology-grounded glossary + the one-prohibition-six-accounts ledger.
  • Theory umbrella — the organizing question, the catalog, and the primitive / exponent-ring / semantic-vs-syntactic splits.
  • Comparison — the formalizations reconciled, the graded-algebra hypothesis tested, the at-a-glance matrix, the consensus, and the Sparkles delta.
  • Prototype evaluation — the thirteen runnable D probes compared across the design axes, with what a Sparkles units library should take from each.

Sources

Each deep-dive carries its own primary-source citations — papers and books (pinned as local artifacts, with editions and page numbers), SHA-pinned source trees for every surveyed implementation, vendor-doc captures where a system is closed-source, and local reproductions (compiler transcripts, codegen diffs) for the load-bearing behavioural claims. The authoritative artifacts behind this index's classifications are:

  • Foundational theory — Buckingham 1914; Bridgman 1922; Drobot 1953; Whitney 1968; Curtis–Logan–Parker 1982; Wand & O'Keefe 1991; Kennedy 1994–2010; Hart 1994/1995; Janyška–Modugno–Vitolo 2007; Tao 2012; Gundry 2015; Raposo 2018/2019; Jonsson 2020/2021; Zapata-Carratalá 2021; Bobbin et al. 2025 — as cited in the theory subtree.
  • Metrology primaries — the VIM (JCGM 200:2012), the SI Brochure (9th ed.), NIST SP 811, the UCUM specification, and the QUDT ontology — as quoted in concepts.
  • Per-system sources — the pinned project source trees, official docs, and papers cited in each linked system page.