[units] (controlled) implicit conversion

Hi, I took much labour in defining an extra system of units (atomic units). It works very well and it also defines (optionaly) default conversion from atomic to SI units. The problem that I have now is that all the conversion has to be done explicitly. I understand that this way of doing thing is by design. But for some formulas I would like to allow implicit conversion, for example when adding energies in SI and energies in atomic units (I don't care which direction the conversion is done since I will transform to one of the two at the end of the formula). On top of that the Units Manual says: "Safety and the potential for unintended conversions leading to precision loss and hidden performance costs. Options are provided for forcing implicit conversions between specific units to be allowed. " The question is which are the "Options provided for forcing implicit conversion"? What follow is an example: What I want is some controlled implicit conversion (even better is this conversion are allowed inside a certain program scope). Note that line 4 doesn't work: quantity<si::energy> e1(3.*si::joules); quantity<atomic::energy> e2(4.*atomic::hartree); quantity<atomic::energy> e3(e1); //works e1 = e2; //doesn't work e1 = quantity<si::energy>(e2); //works cout<<e1<<'\n'<<e2<<'\n'<<e3<<endl; note that the third line works because somewhere I defined a conversion_factor plus a default_conversion between units in the different systems. And it works because the conversion is explicit. Now the fourth line doesn't work, it gives an error (see at end). comenting the third line compiles. I even tried defining a conversion for this particular units, but still doesn't work. BOOST_UNITS_DEFINE_CONVERSION_FACTOR( boost::units::atomic::energy, boost::units::si::energy, double, 4.359744e-18 ); BOOST_UNITS_DEFAULT_CONVERSION( boost::units::atomic::energy, boost::units::si::energy ); error caused by line 4: In file included from /usr/include/boost/units/io.hpp:28, from /home/alfc/prj/mag/Qbox//units/systems/ atomic.hpp:187, from eos.cpp:8: /usr/include/boost/units/quantity.hpp: In member function ‘boost::units::quantity<Unit, Y>& boost::units::quantity<Unit, Y>::operator=(const boost::units::quantity<Unit2, YY>&) [with Unit2 = boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<2l, 1l> >, boost::units::list<boost::units::dim<boost::units::mass_base_dimension, boost::units::static_rational<1l, 1l> >, boost::units::list<boost::units::dim<boost::units::time_base_dimension, boost::units::static_rational<-0x00000000000000002l, 1l> >, boost::units::dimensionless_type> > >, boost::units::homogeneous_system<boost::units::list<boost::units::atomic::electron_mass_base_unit, boost::units::list<boost::units::atomic::elementary_charge_base_unit, boost::units::list<boost::units::atomic::reduced_planck_constant_base_unit, boost::units::list<boost::units::atomic::coulomb_force_constant_base_unit, boost::units::list<boost::units::atomic::boltzman_constant_base_unit, boost::units::dimensionless_type> > > > > >, void>, YY = double, Unit = boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<2l, 1l> >, boost::units::list<boost::units::dim<boost::units::mass_base_dimension, boost::units::static_rational<1l, 1l> >, boost::units::list<boost::units::dim<boost::units::time_base_dimension, boost::units::static_rational<-0x00000000000000002l, 1l> >, boost::units::dimensionless_type> > >, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10l, boost::units::static_rational<3l, 1l> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, Y = double]’: eos.cpp:115: instantiated from here /usr/include/boost/units/quantity.hpp:234: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’ /usr/include/boost/units/quantity.hpp:234: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’ Thank you, Alfredo

I took much labour in defining an extra system of units (atomic units). It works very well and it also defines (optionaly) default conversion from atomic to SI units. The problem that I have now is that all the conversion has to be done explicitly. I understand that this way of doing thing is by design.
Perhaps you would be willing to add the atomic system to the Boost distribution? I expect that there is a reasonable subset of users for whom this would add value...
But for some formulas I would like to allow implicit conversion, for example when adding energies in SI and energies in atomic units (I don't care which direction the conversion is done since I will transform to one of the two at the end of the formula). On top of that the Units Manual says:
"Safety and the potential for unintended conversions leading to precision loss and hidden performance costs. Options are provided for forcing implicit conversions between specific units to be allowed. "
The question is which are the "Options provided for forcing implicit conversion"?
My recollection is that, after much debate, discussion, and contemplation, it was decided that allowing implicit conversions created too many problems and ambiguities, some of them subtle. That being said, it is a common request for functions that take arbitrary units of specified dimension. This is relatively straightforward to accomplish (see these threads for more examples : http://lists.boost.org/boost-users/2009/03/45745.php and http://lists.boost.org/boost-users/2010/04/58340.php) : template<class Y,class System> void f(const quantity<unit<desired_dimension_type,System>,Y>& arg) { const quantity<desired_unit_to_use_for_internal_calculations,Y> q(arg); // do something with q return; } This doesn't solve your specific request for implicit assignment to work, but is the recommended way of doing "implicit" conversion in function arguments. Hope this helps. Matthias
What follow is an example:
What I want is some controlled implicit conversion (even better is this conversion are allowed inside a certain program scope). Note that line 4 doesn't work:
quantity<si::energy> e1(3.*si::joules); quantity<atomic::energy> e2(4.*atomic::hartree); quantity<atomic::energy> e3(e1); //works e1 = e2; //doesn't work e1 = quantity<si::energy>(e2); //works cout<<e1<<'\n'<<e2<<'\n'<<e3<<endl;
note that the third line works because somewhere I defined a conversion_factor plus a default_conversion between units in the different systems. And it works because the conversion is explicit. Now the fourth line doesn't work, it gives an error (see at end). comenting the third line compiles.

Hi Matthias, On Apr 30, 9:17 am, Matthias Schabel <bo...@schabel-family.org> wrote:
Perhaps you would be willing to add the atomic system to the Boost distribution?
Seriously, I would love to. What is the best way to share the code and start the collaboration?
I expect that there is a reasonable subset of users for whom this would add value...
You don't imagine how many. I do quantum chemistry and it is incredible how your library changed the way I write my codes... With the certainty that the equations are dimensionally correct and that I am not messing up with the conversion factors I can concentrate in the real problem.
But for some formulas I would like to allow implicit conversion, for example when adding energies in SI and energies in atomic units (I don't care which direction the conversion is done since I will transform to one of the two at the end of the formula).
My recollection is that, after much debate, discussion, and contemplation, it was decided that allowing implicit conversions created too many problems and ambiguities, some of them subtle.
I understand, and I think the debate is not fruitless.
That being said, it is a common request for functions that take arbitrary units of specified dimension. This is relatively straightforward to accomplish
template<class Y,class System> void f(const quantity<unit<desired_dimension_type,System>,Y>& arg) { const quantity<desired_unit_to_use_for_internal_calculations,Y> q(arg); // do something with q return;
}
This doesn't solve your specific request for implicit assignment to work, but is the recommended way of doing "implicit" conversion in function arguments. Hope this helps.
Actually by looking at your code and my code I realized that it is unreasonable to ask for implicit conversion within normal ('=') assignment. In general assigment is not the cause of the unelegant code with explicit conversion but are the operations inside of a long equation what we should focus in. Besides, operator= can't be overloaded in C++. My example in the original post was misleading because in concentrated in the assignment rather than in the syntax improvement I wanted (mainly being able to add quantities in different systems). It seems that just by taking care of addition and substraction we have 90% of the problem solved, my approach was the following: overload binary operator+ and operator- in a special namespace (e.g. called "si_conversion" --suggestions accepted--). In such a way that the following code works: quantity<si::energy> een1(1.e-17*si::joules); quantity<atomic::energy> een2(2.*atomic::hartree); ---> using namespace boost::units::atomic::si_conversion; //"activates" implicit convertion on addition in the current scope quantity<atomic::energy> een3(een1+een2); // addition works here because operator+(si_unit, atomic_unit) is in scope and this is the code for operator+ and operator-, in principle should work for any physical dimension from atomic system to si system. namespace boost{ namespace units{ namespace atomic{ namespace si_conversion{ template<class Dimension, class Y> quantity<unit<Dimension, atomic::system>, Y> operator+( quantity<unit<Dimension, atomic::system>, Y> const& e1, quantity<unit<Dimension, si::system >, Y> const& e2 ){ return e1+quantity<unit<Dimension, atomic::system>, Y>(e2); // or e1 + (quantity<atomic::energy, Y>)e2; ??? } template<class Dimension, class Y> quantity<unit<Dimension, atomic::system>, Y> operator+( quantity<unit<Dimension, si::system >, Y> const& e1, quantity<unit<Dimension, atomic::system>, Y> const& e2 ){ return quantity<unit<Dimension, atomic::system>, Y>(e1)+e2; } template<class Dimension, class Y> quantity<unit<Dimension, atomic::system>, Y> operator-( quantity<unit<Dimension, atomic::system>, Y> const& e1, quantity<unit<Dimension, si::system >, Y> const& e2 ){ return e1-quantity<unit<Dimension, atomic::system>, Y>(e2); } template<class Dimension, class Y> quantity<unit<Dimension, atomic::system>, Y> operator-( quantity<unit<Dimension, atomic::system>, Y> const& e1, quantity<unit<Dimension, atomic::system>, Y> const& e2 ){ return quantity<unit<Dimension, atomic::system>, Y>(e1)-e2; } }}}} Thank you Alfredo

-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of alfC Sent: Tuesday, May 04, 2010 4:03 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] [units] (controlled) implicit conversion
On Apr 30, 9:17 am, Matthias Schabel <bo...@schabel-family.org> wrote:
Perhaps you would be willing to add the atomic system to the Boost distribution?
Seriously, I would love to. What is the best way to share the code and start the collaboration?
I expect that there is a reasonable subset of users for whom this would add value...
You don't imagine how many. I do quantum chemistry and it is incredible how your library changed the way I write my codes... With the certainty that the equations are dimensionally correct and that I am not messing up with the conversion factors I can concentrate in the real problem.
I'm pleased that you have been able to press the Boost.Units library into serious service. And I'm really delighted that you have found that it really does achieve the gains in reliability, confidence and convenience that many of us wanted from this, but had not dared to believe was possible (gosh - it's a decade ago). Until Matthias Schabel and Steven Watanabe worked their meta magic on it :-) I hope your collaboration can show how it can be further improved into an area where mixed very large and very small units are a real problem. And I hope it will show that the library can be used for tricky problems as well as the more mundane (but still error prone) and thus help achieve really widespread use of the Boost.Units library. Good luck. Paul PS Steven Watanabe has recently developed yet more cunning metacode to allow autoprefixing the SI units. quantity<length> l = 123456. * meters; // A quantity of length, in units of meters. cout << engineering_prefix << l << endl; // Outputs "123.456 km" - because more than 999.9 meters. (also a << binary_prefix and no prefix of course) This is *very* convenient to avoid values flipping into the nasty E format. Hopefully this will appear in future releases.
participants (3)
-
alfC
-
Matthias Schabel
-
Paul A. Bristow