Git Product home page Git Product logo

Comments (19)

mpusz avatar mpusz commented on June 11, 2024

Related issue #31.

from mp-units.

kwikius avatar kwikius commented on June 11, 2024

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.

mpusz avatar mpusz commented on June 11, 2024

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.

kwikius avatar kwikius commented on June 11, 2024

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.

kwikius avatar kwikius commented on June 11, 2024

Actually I am starting to change my mind. Maybe the multiplier syntax is not so bad :)

from mp-units.

mpusz avatar mpusz commented on June 11, 2024

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.

mpusz avatar mpusz commented on June 11, 2024

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.

i-ky avatar i-ky commented on June 11, 2024

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.

mpusz avatar mpusz commented on June 11, 2024

@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.

kwikius avatar kwikius commented on June 11, 2024

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';

https://godbolt.org/z/_LcyNt

That doesnt happen with UDLs'.

from mp-units.

kwikius avatar kwikius commented on June 11, 2024

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.

oschonrock avatar oschonrock commented on June 11, 2024

I think we need feedback from a wider audience on this.

It might make sense to retain both options.

from mp-units.

mpusz avatar mpusz commented on June 11, 2024

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 for quantity 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.

JohelEGP avatar JohelEGP commented on June 11, 2024

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.

JohelEGP avatar JohelEGP commented on June 11, 2024

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.

kwikius avatar kwikius commented on June 11, 2024

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.

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.

kwikius avatar kwikius commented on June 11, 2024

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.

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.

JohelEGP avatar JohelEGP commented on June 11, 2024

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.

JohelEGP avatar JohelEGP commented on June 11, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.