mp-units icon indicating copy to clipboard operation
mp-units copied to clipboard

feat!: composable symbols

Open JohelEGP opened this issue 7 months ago • 11 comments

feat!: composable symbols

My original intent with "symbols" was to have composable 1-letter symbols that can describe units. For example, m for metre and mm for millimetre, all with the same m in code. Instead, we got the product "unit prefix × unit symbol". So on top of m, we have mm and m3.

I think we should explore my original intent. I'm not suggesting to remove mm or m3. What I'm suggesting is to enable defining mm in terms of m. This allows users to not have to pre-define prefixed versions of their units.

master feat!
x * m x * m
x * mm x * m(m)

There's only one m (per system, so x * m keeps meaning "x SI metres"). Its meaning is contextual, much like in paper calculations. The rules for composition are described in the SI Brochure §3 "Decimal multiples and sub-multiples of SI units". Although m.m is a possible syntax, m(m) supports program-defined units such as M(px).

Abusing ^ for power:

master feat! clang-formats as
x * m3 x * (m^3) x * (m ^ 3)
N/A x * m(m^3) x * m(m ^ 3)

Abusing ^ for power would require constexpr parameters. Lately, there's interest in that direction: https://github.com/cplusplus/papers/issues/1458#issuecomment-1812540792.

Examples:

An implementation using the version 2.0.0: https://godbolt.org/z/cd8qjrdxe.

#include <mp-units/systems/si/si.h>

using namespace mp_units;
using namespace mp_units::si::unit_symbols;

namespace ns {
  template<template<PrefixableUnit auto U> class Prefix, Unit auto U> struct prefix_or_unit : decltype(U) {
    template<PrefixableUnit U2> consteval Unit auto operator()(U2) const { return Prefix<U2{}>{}; }
  };
  inline constexpr struct m : prefix_or_unit<si::milli_, ::m> { } m;
}

static_assert(2 * m == 2 * ns::m);
static_assert(2 * mm == 2 * ns::m(ns::m));
master feat!
include/mp-units/systems/si/unit_symbols.h
inline constexpr auto mm = milli<metre>; inline constexpr auto mm = m(m);
example/spectroscopy_units.cpp
isq::frequency(1. * THz) isq::frequency(1. * T(Hz))
isq::wavelength(1. * um) isq::wavelength(1. * u(m))
example/total_energy.cpp
sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c))) ^ for quantities too?
isq::momentum(4. * GeV / c) isq::momentum(4. * G(eV) / c)
QuantityOf<isq::mass> auto m1 = 3. * GeV / c2 QuantityOf<isq::mass> auto m1 = 3. * G(eV) / (c^2)
p1.in(kg * m / s) p1.in(k(g) * m / s)

JohelEGP avatar Nov 27 '23 14:11 JohelEGP