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

How to constrain a derived unit for a specific quantity kind?

Open mpusz opened this issue 1 year ago • 11 comments

I just played with a simple example:

inline constexpr struct fuel_consumption final : quantity_spec<isq::volume / isq::length> {} fuel_consumption;
inline constexpr auto l_per_100km = si::litre / (mag<100> * si::kilo<si::metre>);

quantity q1 = 5.8 * l_per_100km;
quantity q2 = fuel_consumption(6.7 * l_per_100km);

static_assert(q1.dimension == isq::area.dimension);
static_assert(q2.dimension == isq::area.dimension);
static_assert(implicitly_convertible(q1.quantity_spec, isq::area));
static_assert(!castable(q2.quantity_spec, isq::area));

it was really nice until now, but then I noticed that I can do the following 😱:

quantity q3 = q1.in(m2);
quantity q4 = q2.in(m2);
quantity q5 = isq::area(42 * l_per_100km);
quantity<isq::area[m2]> q6 = 42 * l_per_100km;

Do we have any ideas on how to improve here?

mpusz avatar Oct 01 '24 17:10 mpusz

The same could be used to constrain N m to be used only with moment of force or V A to be used with apparent power.

mpusz avatar Oct 01 '24 17:10 mpusz

There are several problems here:

  1. Derived units are not predefined in the code (they are dynamically composed as a result of unit equations), so there is no class template defined by the user where we could provide such a constraint.
  2. What about the scaled versions of those? Even if we invent some type trait to externally opt-in m2 as a unit of area, what about cm2 and others?
  3. Such a type trait would be inconsistent with what we have for named units already. For consistency, we could be forced to move the support of all the units to a type trait. This is cumbersome, requires more than one line for a unit definition, and would break our users.

mpusz avatar Oct 01 '24 17:10 mpusz

The same could be used to constrain N m to be used only with moment of force or V A to be used with apparent power.

This is backwards.

N * m should be unconstrained. Moment of force can require N * m.

JohelEGP avatar Oct 01 '24 18:10 JohelEGP

Well, it has at least two problems as well:

  1. moment of force is a quantity being a part of the system of quantity, and those should be units agnostic.
  2. moment of force can also at least use kg m^2 s^-2 so it can't require only one unit.

mpusz avatar Oct 01 '24 18:10 mpusz

You're right, quantities are unit-agnostic in the ISQ.

A number and a reference together form a quantity value. A unit is just that, but defined and adopted by convention.

In mp_units' code, however, they're different. So you might want to replicate for units what makes quantity q5 = isq::area(q2); fail for quantity.

Or you can make l_per_100km a quantity of fuel_consumption, and it (mostly?) works: https://godbolt.org/z/jEaffYbxx.

JohelEGP avatar Oct 01 '24 19:10 JohelEGP

Interesting approach 😉 It has the "chicken egg problem", though. How can we define the first quantity in terms of a unit that is a quantity? Also, I wouldn't like to embed a representation type and its value into unit definitions.

mpusz avatar Oct 01 '24 19:10 mpusz

So you might want to replicate for units what makes quantity q5 = isq::area(q2); fail for quantity.

By this, I think making what a quantity kind does for quantity, but for units.

If

inline constexpr struct fuel_consumption final : quantity_spec<isq::volume / isq::length> {} fuel_consumption;

makes

static_assert(!castable(q2.quantity_spec, isq::area));

work, then perhaps

inline constexpr struct l_per_100km final : unit_spec<si::litre / (mag<100> * si::kilo<si::metre>)> {} l_per_100km;

could make

quantity q4 = q2.in(m2);
quantity q5 = isq::area(42 * l_per_100km);
quantity<isq::area[m2]> q6 = 42 * l_per_100km;

not work.

JohelEGP avatar Oct 01 '24 19:10 JohelEGP

I am afraid that even though it could improve the case here, it would break plenty of other use cases. For example, https://mpusz.github.io/mp-units/latest/users_guide/framework_basics/systems_of_units/#many-shades-of-the-same-unit.

Units have very different rules than quantities, and we probably should not try them to work the same.

mpusz avatar Oct 01 '24 19:10 mpusz

Just leave those units and examples untouched. An "unit kind"s would be, specifically, for use cases like those in this issue.

JohelEGP avatar Oct 01 '24 19:10 JohelEGP

Side question: for something like volume / length, are we doing the Anthony Williams thing of not simplifying numerator and denominator? Or is it just already basically equivalent to area?

chiphogg avatar Oct 02 '24 00:10 chiphogg

We never simplified volume / length. This was always mp-units thing ;-) We simplify only the same type identifiers.

mpusz avatar Oct 02 '24 10:10 mpusz