> I have found in the past that there is a need to > distinguish between dimension handling and unit handling. > > In the case of a physical calculation, I usually ensure that > the code works with a self consistent set of units, and thus > only need dimensionality, compile time, code. > > Units then become important only in the user interface, and > I have a list of the units used in the physical calculation > for each dimension. > > This is obviously only one way of using dimensions and units, > but I think an important one. The usual exception to the above > is for money where you are working with multiple currencies.
I agree that this is an important distinction which some people get confused on. Reviewing our old discussions, this was the closest thing to a concensous. Money was the one issue that was still very much up in the air. My conclusion was that money probably warranted a whole library to itself, but that many users would be happy with a simple money dimension tacked onto SI. > A couple of use cases, that I am unsure would be handled by the > current proposal: > I have a "Cost" class that records costs for different factories > in different countries. The "unit" used for each is factory > is different, eg USD for factories in US, GBP for those in UK. > ie the unit varies per instance. I agree that treating value as the dimension, but I choose to use currency as the name of the dimension, since value has other connotations to programers. There are several ways you could deal with this with my draft library. Users would choose the most appropriate way for their particular purposes. One way involves treating USD, GBP, etc. as units for the currency dimension. The other involves treating USD, GBP, etc. as qualifiers for the type of currency. One way is to decide that what you're really interested in is the value, and you're not really interested in which currency that is in. Such a user could use the currency dimension something like this... static const currency usd (1.00); static const currency gbp (1.50); currency chicago_cost = 2000 * usd; currency dublin_cost = 1500 * gbp; currency total_cost = chicago_cost + dublin_cost; cout << "The total cost is " << total_cost << " = " << total_cost / usd << " USD = " << total_cost / gbp << " GBP\n"; The advantage of this way is that the user can do arithmetic between different currencies transparently. If all the user is interested in is the value in their home currency, then this may be adequate and even desirable. Of course, there are cases where this would not be appropriate. For example, if a user wants to keep track of how much of his money is in different currencies, a common desire given that the relative values of currencies fluctuate. In such a case, I would recommend making use of my qualifier tags. Something like... char usd_label[] = "USD"; char gbp_label[] = "GBP"; typedef basic_qualifier<usd_label> usd_qualifier; typedef basic_qualifier<gbp_label> gbp_qualifier; typedef basic_qualifier<euro_label> euro_qualifier; typedef qualified_dimension<currency,usd_qualifier> usd; typedef qualified_dimension<currency,gbp_qualifier> gbp; typedef qualified_dimension<currency,euro_qualifier> euro; static const usd dollar (1.00); static const gbp gb_pound (1.00); usd chicago_cost (2000.); // just to show another way usd la_cost = 1800. * dollar; gbp dublin_cost = 1500. * gb_pound; usd total_us_cost = chicago_cost + la_cost; // same currency, so ok usd total_cost = total_us_cost + dublin_cost; // different currencies: WILL NOT COMPILE BY DEFAULT This way the compiler will prevent you from assigning or performing arithmetic between currencies (unless a user want to allow such operations and specializes the is_tag_change_ok<> and/or promote_dimension_qualifier<> templates accordingly). Now a user who wants to keep track of all her bank accounts in different currencies will do so with strongly typed variables. Of course, they might want to write a class that allows for combining these into a single value in some time dependant fashion (and most likely not possible at compile time). > A similar situation occurs for "dimensions" of physical units. > eg. if you want a list of quantities used per output weight > or output pieces, then each item in the list has different > dimensions, eg. Watt seconds/time, Litre/piece, number/kg. > In this case I obviously have to give up the type checking, > but still need to be able to record a dimension, to allow > display in appropriate units. I think this could be addressed with something like list<any> materials; materials.push_back(100.*joule); materials.push_back(50.*liter); cout << "This will take: " for(list<any>::iterator i = materials.begin();i!=materials.end();++i) cout << " " << *i << "\n"; Now, it's probably obvious that the 100 joules is of electricity, but may not be so obvious what the 50 liters is of. If you'd like to keep track of what those fifty liters are of, then I'd recommend you use a qualifier tag like: char garlic_label[] = "garlic"; typedef basic_qualifier<garlic_label> garlic_qualifier; ... materials.push_back(qualify<volume,garlic_qualifier>(50. * liter)); I hope this makes sense and addresses some common concerns. BTW- Thanks to all those who have offered help with type promotion, the time issue, and testing with MSC++. Provided boosers basically support my draft's layour, I will try to incorporate what I learn from your posts into the next version I post. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost