mpusz / mp-units

The quantities and units library for C++
https://mpusz.github.io/mp-units/
MIT License
1.07k stars 85 forks source link

Do quantity kinds form a hierarchy? #429

Closed mpusz closed 1 year ago

mpusz commented 1 year ago

As ISO 80000 states, quantities of the same kind are comparable, addable, and subtractable. With that, we can create kinds of frequency, radioactivity, and modulation_rate, where all of them have dimension 1 / dim_time to prevent addition and subtraction on them. So 1 * Hz + 1 * Bq + 1 * Bd will not work.

On the other hand, we have several quantities of energy which probably should become a kind as well. Especially since there is no way to explicitly derive one definition from another as, for example, kinetic_energy is defined as m V²/2. However, this means that the following will not compile:

quantity<isq::mechanical_energy, int> e_m = isq::potential_energy(42 * J) + 85 * kg * pow<2>(2 * m / s) / 2;

because the rhs is a quantity of isq::mass * isq::length² / isq::time² rather than isq::energy kind.

In order to make it compile, we will have to explicitly convert the rhs of addition to an energy quantity with something like:

quantity<isq::mechanical_energy, int> e_m = isq::potential_energy(42 * J) + isq::kinetic_energy(85 * kg * pow<2>(2 * m / s) / 2);

Also, please note that most probably:

quantity<isq::mechanical_energy, int> e_m = 85 * kg * pow<2>(2 * m / s) / 2;

will work without any explicit conversion because, at least as of now, for interconvertibility, we check interconvertibility of the ingredient quantities and ignore kinds.

One possible way is to acknowledge a hierarchy of kinds so isq::kinetic_energy(85 * kg * pow<2>(2 * m / s) / 2) is both of the isq::energy and isq::mass * isq::length² / isq::time² kinds rather than just of isq::energy kind. This, however, would make this work 1 * Hz + 1 * Bq + 1 * Bd, and the result would be of 1 / isq::time kind. Even worse, the following would also work:

quantity<isq::frequency, int> f = 1 * Hz + 1 * Bq + 1 * Bd;

Does it make any sense at all? Do you have any ideas on how to improve here? Maybe we should not try to provide any type-safety for kinds at all, but then the following would work, which bothers me a lot:

void foo(quantity_of<isq::width> w, quantity_of<isq::height> h);

foo(isq::height(42 * m), isq::width(42 * m));  // the arguments are provided in the incorrect order
mpusz commented 1 year ago

BTW, the rationale for making an energy a distinct kind is the following quote from the SI Brochure:

In practice, with certain quantities, preference is given to the use of certain special unit names to facilitate the distinction between different quantities having the same dimension. When using this freedom, one may recall the process by which this quantity is defined. For example, the quantity torque is the cross product of a position vector and a force vector. The SI unit is newton metre. Even though torque has the same dimension as energy (SI unit joule), the joule is never used for expressing torque.

So J should be defined as a quantity only valid for energy kind, the same as we agreed to define Hz to be used only with a frequency kind.

mpusz commented 1 year ago

Done in V2.