Comments (19)
Related issue #31.
from mp-units.
UDLs are simple shorter and neater so get my vote . Ultimately if they have to have slightly longer names then that is not a problem as far as I am concerned.
UDLs is a neat idea that unfortunately causes very short names to appear in global scope due to unqualified lookup only allowed.
Reserving literals operator names without underscores to the standard namespace didnt solve anything anyway since they are so useful that they are already colliding in std namespace :)
A nice solution would be to extend UDL rules to allow qualified lookup. Here is one possible syntax. I think scope-resolution-operator followed by a number is syntactically available
auto x1 = si::1mm;
auto x2 = si :: 1 mm; // with the scope resolution operator prefix
// pretty spaces should be parsable
That would bring them to a similar functionality to inline constants.
EDIT: Actually lthe above syntax could mean that if si::mm is a type with an explicit constructor taking an int, construct a constexpr object of that type with that argument. No literal operator required!
Meanwhile the obvious pragmatic workaround is to attach a postfix namespace to avoid collisions which are otherwise inevitable as use grows
auto x2 = 1l_si;
from mp-units.
Qualified lookup for UDLs was discussed already in the ISO C++ Committee but if I recall correctly it did not fly (at least so far). But even if it did it would solve only point 3 from the above list. Still, we cannot easily create some UDLs and long names do not help in some cases (i.e. erg
or ergps
). Also as I noted in point 2 UDLs help only when we have compile-time known constant. Otherwise, we have to decay to the long form of variable initialization.
But yes, I also always hated the "multiply" syntax to form quantities but it seems it actually may have some benefits over UDLs.
from mp-units.
There is another option. Just use a temporary as you show above,
I show again my typedef syntax which works very well and could be used by mpusz units . It contains all the information required in the shortest form for the commonest quantities and coherent units
length::mm{1}
// or ...
length::mm<>(1) // to expose the value_type default to double
Anyway, certainly worth looking at where and how often the use of such constants occurs in real world. How common is it and is it necessary to define constants at global scope versus just temporaries with explicit initialisers as I used to do before UDLs? (N.B. Discussing quality of my code and how it could be improved is not the point here ;). It is just shown as an example of day to day use. The code could certainly benefit by review, upgrading to UDLs etc,etc)
To answer point1 I would take the UDL where it works and use the temporary where not
Initialisation is a very common programming chore in application development.
Looking through my code I tend to try to use a short local typedef and then a rvalue with explicit number init for a constant ( remembering I used these types for many years before UDLs were available)
https://github.com/kwikius/aerofoil/blob/master/aerofoilDoc.cpp#L11
// mm is typedef in class definition, could be replaced by mpusz quantity
https://github.com/kwikius/aerofoil/blob/master/aerofoilDoc.hpp#L21
I think using 1 * si::mm here would start to get on my nerves!
in for loop you would hope for a terse syntax.
https://github.com/kwikius/quan-trunk/blob/master/quan_matters/examples/capacitor_time_curve.cpp#L55
for ( auto t = 0ms ; t <= timeout; ++t ){ //nice when it works !
for ( auto t = 0 * si::ms ; t <= timeout; ++t ){ // maybe !
for ( auto t = si::0ms ; t <= timeout; ++t ){ // maybe !
In class constructors generally I found explicit init with an explicit value easiest), so UDL irrelevant
https://github.com/kwikius/mavlink_to_frsky/blob/master/stm32f4/aircraft.hpp#L83
Another answer : Provide both options for now ... :)
from mp-units.
Actually I am starting to change my mind. Maybe the multiplier syntax is not so bad :)
from mp-units.
Hehe, I see you are going the same path as I did. My initial opinion was also "yack, it is an awful and old way to do it" ;-)
from mp-units.
With constants, we could also consider more extensions like:
inline constexpr auto km = k * m;
inline constexpr auto kmph = km/h;
But as we discussed in another thread that will work against the downcasting facility as the user is never providing a user-friendly name for a target type.
from mp-units.
with constants those 2 cases would look like:
auto v1 = 120 * km / 2 * h; auto v2 = length * km / duration * h;
Won't these expressions produce km×h instead of km/h?
from mp-units.
@i-ky You are right, I do not have experience with this syntax and did not notice that. But it seems it is a good point against the "multiply" syntax. I will fix the code sample in polls above, thanks!
from mp-units.
Another point against UDLs. Arbitrary expressions are not allowed
auto x = (1./4)sq_m; // error
But a major point against constants is that they clog up the global namespace with many tiny names , h, s, etc. and that could be a real headache in real scale code .
auto constexpr v1 = 10 * m/s;
std::cout << v1 << '\n';
double constexpr s = 2.0;
auto v2 = 20 * m/s;
std::cout << v2 << '\n';
That doesnt happen with UDLs'.
from mp-units.
Personally I dont think item 1 regarding initialisation of quantitites by runtime numeric values on the list above is a problem in practise. Generally a variable quantity is initialised with a constant , but once initialised, it is the quantity that is being used as the runtime variable. Where the UDL syntax lacks recommend to use a temporary.
In light of my point about name hiding in the post above, I think that UDLs are the right way to go. Since it is not possible to use qualified lookup in current c++, the only other option is to add a namespace to the name itself as in the good old C days.
So for example reserve the Q_ prefix for use by std::quantity literals
auto v1 = 10.0Q_F;
auto v2 = 10.0Q_J;
auto v3 = 10.0Q_W;
auto v4 = 10.0Q_K;
auto v5 = 10.0Q_d;
auto v6 = 10.0Q_l;
auto v7 = 10.0Q_L;
auto v8 = 10.0Q_erg;
auto v9 = 10.0Q_ergps;
EDIT: in line with everything is std being lowercase, and also becase it is easier to read against the preceding digit. Anyway the style has a lot of appeal to me as I test it. The uniform prefix lets you know immediately that the type is a quantity, rather than for example a chrono duration or another name for a long
auto v1 = 10.0q_F;
auto v2 = 10.0q_J;
auto v3 = 10.0q_W;
auto v4 = 10.0q_K;
auto v5 = 10.0q_d;
auto v6 = 10.0q_l;
auto v7 = 10.0q_L;
auto v8 = 10.0q_erg;
auto v9 = 10.0q_ergps;
That solves all items. I think it is correct that the si units take precedence over the other less complete unit systems. SI is the dominant system for very good reason. For disambiguating non si units, then just extend the namespace. The extra ugliness is justified:
auto v10 = 10.0Q_imp_in;
from mp-units.
I think we need feedback from a wider audience on this.
It might make sense to retain both options.
from mp-units.
I think q_
prefix has a lot of sense. I will make this change soon. It will address #31.
Also, during the last ISO discussion it was raised that there should be a dedicated operator:
quantity<Dim, U, Rep> operator*(Rep v, magic_type<Dim, U>);
It will only allow the syntax 3 * s
where:
inline cosntexpr magic_type<dim_time, second> s;
- It will solve the issue with
op/
(as it will be an illegal operation) - We can deduce
Rep
forquantity
from the LHS type of the operator - It is easy to disambiguate different systems
I think that both options seem interesting and thus we will probably provide both for now and get some more field experience with both of them. Do you have any suggestions on how to name a magic_type
?
from mp-units.
Both options are the way to go. Sometimes you want to encode a constant, others, do apples / h
, which I prefer very much over apples / hours{1}
.
I like magic_type
, so I don't have to write apples / h<int>
(like with std::numbers
). But you mention that operator/
would be ill-formed. I think everything should be allowed everywhere.
I make a point for having a natural syntax when writing formulas with a units library at nholthaus/units#196. In C++20, you can write 1970y/January/1
. A units library shouldn't lose to that.
Looking for formulas at https://en.wikipedia.org/wiki/Formula, we see:
units::pow<3>(cm)
should work and be the intuitively expected magic_type
specialization.
Some formula look like A = x * u1 * u2 / u3, where ux are units. Maybe I have a quantity
a
representing x * u2 / u3
, so I only need to do A(a * u1)
in C++.
I think magic_type
should just be a quantity
with a library-defined representation type that does the right thing when it is involved in an operation with any other representation type, so that everything else remains unchanged.
from mp-units.
On a second thought, there'd be cm3
, so units::pow<3>(cm)
is too round-about, but feasible still when the library doesn't have such constant. Also, point 2 in the OP still applies to the names of these constants.
Another advantage of constants relates to the N*M problem. The library only offers q_m_per_s
and q_km_per_h
, but maybe I want q_km_per_s
. With constants, this isn't a problem.
from mp-units.
On a second thought, there'd be
cm3
, sounits::pow<3>(cm)
is too round-about, but feasible still when the library doesn't have such constant. Also, point 2 in the OP still applies to the names of these constants.Another advantage of constants relates to the N*M problem. The library only offers
q_m_per_s
andq_km_per_h
, but maybe I wantq_km_per_s
. With constants, this isn't a problem.
A major practical problem with global constants is they can be hidden by local constants of the same name :
// some short name global constant
double constexpr s = 0.5;
//----------------------------------
#include <iostream>
int main()
{
constexpr auto a=1.,b=2.,c=3.,s=0.,k=5.;
double y = 1;
auto z = y / s ; //<< --- ouch!
std::cout << z << '\n';
}
from mp-units.
Another advantage of constants relates to the N*M problem. The library only offers
q_m_per_s
andq_km_per_h
, but maybe I wantq_km_per_s
. With constants, this isn't a problem.
In PQS I solved the problem of ad-hoc units by creating a so-called unit_binary_op that models the pqs::unit concept while providing customised output
Here is how an ad-hoc quantity can be created in source code
https://github.com/kwikius/pqs/blob/master/examples/fountain.cpp#L48
output :
PQS fountain power example
Demo of ad-hoc output units
spray height = 0.6 m
volume per s = 32.3202 cm³⁄s // <----------- Here is the custom output
mass per s = 32.3202 g⁄s // here is another ad-hoc unit
fountain output power = 0.190043 W
I show si units there but you can also use non-si /si combination of course and also stack them together
from mp-units.
There's also the case of linear algebra and other quantity wrappers.
using namespace units::physical::si;
fs_vector<si::length<si::metre>, 3> v = { 1_q_m, 2_q_m, 3_q_m };
fs_vector<si::length<si::metre>, 3> v = fs_vector<int, 3>{ 1, 2, 3 } * 1_q_m;
fs_vector<si::length<si::metre>, 3> v = fs_vector<int, 3>{ 1, 2, 3 } * m;
auto v = fs_vector<int, 3>{ 1, 2, 3 } * 1_q_m;
auto v = fs_vector<int, 3>{ 1, 2, 3 } * m;
si::length<si::metre, fs_vector<int, 3>> v(fs_vector<int, 3>{ 1, 2, 3 });
Do you think unit constants are an improvement here?
from mp-units.
A major practical problem with global constants is they can be hidden by local constants of the same name :
This can be mitigated by using the dimension concepts. Another reason to standardize them.
from mp-units.
Related Issues (20)
- Should `quantity_point_like_traits` work on raw values?
- Consider using two types instead of values for the template parameters of the `reference` type HOT 1
- Bikeshedding `force_in(Unit)` HOT 10
- Change `mp-units/2.1.0` to `mp-units/2.0.0` in Conan installation steps? HOT 2
- Add support for easier math expressions in `mp-units/math.h` HOT 17
- Should we allow deriving from system entities? HOT 2
- No 2.1.0 in Conan center HOT 3
- ice_point definition is (very very slightly) incorrect
- Do we really need ASCII-only text output? HOT 13
- Text input support
- formatting/printing vector of quantities results in compile time error HOT 3
- Bazel build system support HOT 3
- Should conversions from the raw numerical value to a dimensionless quantity with a unit one be allowed? HOT 26
- Is mp-units targeting freestanding implementations HOT 6
- Provide `wchar_t` support for text output
- Effectively global unit names like 'm' are problematic HOT 35
- compilation time and how to improve it HOT 17
- Can't compile with localization disabled HOT 1
- Can't compile with exceptions disabled HOT 1
- Linker error with base units for "numerical_value_in()" HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mp-units.