An affine unit – the most common case being a unit that is related to other units representing the same physical quantity not by a scale factor, but by a shift in the zero point.

This is not a fundamentally new concept, adding a constant offset could just be implemented in a custom conversion function as well (see the UnitImpl documentation). However, Quantity is specialized on affine units such as to only provide operations which make sense for them:

Informally speaking, an affine space is a vector space which »forgot« its origin, its elements are points, not vectors. Thus, a quantity of an affine unit cannot be added to another (as it makes no sense to add two points), but like vectors can be added to points to yield a new point, a quantity of the underlying base unit can be. Also, two affine quantities can be substracted to yield a quantity of the base unit (just as two points can be substracted to get a vector pointing from one to another).

The most common example for this are units of temperature like degrees Celsius or Fahrenheit, as demonstrated below.

  1. struct AffineUnit(BaseUnit, alias toBaseOffset, string name, string symbol = null)
  2. template AffineUnit(alias baseUnit, alias toBaseOffset, string name, string symbol = null)
    template AffineUnit (
    alias baseUnit
    alias toBaseOffset
    string name
    string symbol = null
    ) if (
    ) {}
  3. auto affine(U u)


1 enum celsius = affine!(273.15, "degrees Celsius", "°C")(kelvin);
2 auto t = 3.0 * celsius;
3 t += 1.0 * kelvin; // adding Kelvin is okay
4 assert(!__traits(compiles, t += 2.0 * celsius)); // adding Celsius is not
5 writeln(t - 0.0 * celsius); // 4 Kelvin, not degrees Celsius