-
Notifications
You must be signed in to change notification settings - Fork 78
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
feat!: composable symbols #520
Comments
I have mixed feelings about this feature. On one side I admire the cleverness, on the other side I think it tries to be too clever ;-) I also am not sure what is the intent. Initially I thought it is to limit the number of definitions needed for the standardization process but you stated that "I'm not suggesting to remove mm or m3." If all the prefixed symbols have to remain than what is the rationalle for this feature? User always may write: constexpr auto mm = si::milli<si::metre>; and use it with a short name without the need to include all the "garbage" from |
Yes, if we get |
Yeah, my original intention was to never even have a symbol like
|
I thought about having helpers like that before but decided that: quantity q = 42 * k(m); is too much syntax noise and it is actually not that easy to read at all. If this was the only thing exposed in the library interface I would probably encourage in the docs to the following anyway: constexpr auto km = k(m); And then it is not much different from: constexpr auto km = si::kilo<si::metre>; or constexpr auto km = si::kilo<m>; so having those additional short helpers does not really buy us anything. |
Yeah,
That's because you're defining them or encouraging them. The difference between being able to do Consider if I defined To achieve mp-units level of API, I would have to pre-define pixel for all SI multiples. For generic programming, I mean things like template<PrefixableUnit auto U> auto my_algo(…) { … 42 * kilo<U> … } // Today.
template<PrefixableUnit auto U> auto my_algo(…) { … 42 * k(U) … } // Proposed. I have no concrete use cases of such a generic interface in mind, though. |
Sure, adding such a symbol is a short, simple line, as I stated above. So, even if you do not predefine scaled units, a user may easily add those. I don't like the syntax of constexpr auto Mpx = M(px); is not a big win over: constexpr auto Mpx = si::mega<px>; At least not big enough to excuse adding a new abstraction to the library. |
BTW, we can discuss again if prefixes should be variable templates or functions. I personally prefer variable templates as those in the code resemble better types visible in compile-time errors. Functions on the other hand could benefit from ADL as you stated some time ago. |
I had thought about adding prefix symbols to Au a while ago. I quickly dismissed it as unworkable because That said, I think my overall opinion is in line with this comment:
Expanding on this: the common way to bring in a symbol will be a single using declaration per symbol at the top of a using au::symbols::h;
using au::symbols::m;
// Bringing in a `km` symbol.
//
// With currently available methods:
constexpr auto km = kilo(m);
// With prefix symbols:
constexpr auto km = k(m);
std::cout << v.as(km / h); The only potential benefit I could see is if we want to enable people to stop defining these symbols in the first place, and instead compose them on the fly. That's genuinely novel and not something we could do today: std::cout << v.as(k(m) / h); However, we already need to add a line for each pre-existing symbol that we want to use, so it's probably simplest to do this for the composed symbols as well. While I'm very impressed by the creativity, I agree that it probably doesn't justify the added complexity of what something like |
By the way: I was surprised to see every single prefixed symbol defined in the library. This strikes me as a lot of extra work, a lot of "paying for what you don't use". Given that:
I think we'd be better off deleting all of the prefixed symbols, and telling users how to define their own. (This is Au's approach.) |
I am not sure which approach is better, and for sure we should provide those as alternatives in P3045. I am sure that plenty of people would like to have things like |
With composable symbols, you don't need to do that. For example, today: void f() {
using lib::h;
using lib::m;
auto km = lib::kilo<m>;
auto mm = lib::milli<m>;
… km … mm … h …;
} With composable symbols: void f() {
using lib::h;
using lib::m;
… k(m) … m(m) … h …;
} You don't even need to introduce |
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 havemm
andm3
.I think we should explore my original intent.
I'm not suggesting to remove
mm
orm3
.What I'm suggesting is to enable defining
mm
in terms ofm
.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, sox * 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 asM(px)
.Abusing
^
for power:master
feat!
clang-format
s asx * m3
x * (m^3)
x * (m ^ 3)
x * m(m^3)
x * m(m ^ 3)
Abusing
^
for power would requireconstexpr
parameters.Lately, there's interest in that direction: cplusplus/papers#1458 (comment).
Examples:
An implementation using the version 2.0.0: https://godbolt.org/z/cd8qjrdxe.
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)
The text was updated successfully, but these errors were encountered: