Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mpusz opened this issue Oct 1, 2024 · 11 comments
Open

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

mpusz opened this issue Oct 1, 2024 · 11 comments
Labels
design Design-related discussion enhancement New feature or request
Milestone

Comments

@mpusz
Copy link
Owner

mpusz commented Oct 1, 2024

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 mpusz added the bug Something isn't working label Oct 1, 2024
@mpusz mpusz added this to the v2.4.0 milestone Oct 1, 2024
@mpusz
Copy link
Owner Author

mpusz commented Oct 1, 2024

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
Copy link
Owner Author

mpusz commented Oct 1, 2024

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.

@JohelEGP
Copy link
Collaborator

JohelEGP commented Oct 1, 2024

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.

@mpusz
Copy link
Owner Author

mpusz commented Oct 1, 2024

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.

@JohelEGP
Copy link
Collaborator

JohelEGP commented Oct 1, 2024

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.

@mpusz
Copy link
Owner Author

mpusz commented Oct 1, 2024

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.

@JohelEGP
Copy link
Collaborator

JohelEGP commented Oct 1, 2024

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.

@mpusz
Copy link
Owner Author

mpusz commented Oct 1, 2024

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.

@JohelEGP
Copy link
Collaborator

JohelEGP commented Oct 1, 2024

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

@chiphogg
Copy link
Collaborator

chiphogg commented Oct 2, 2024

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?

@mpusz
Copy link
Owner Author

mpusz commented Oct 2, 2024

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

@mpusz mpusz added enhancement New feature or request design Design-related discussion and removed bug Something isn't working labels Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design Design-related discussion enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants