I wrote such a type library myself, and it worked great. However we eventually realized it was the wrong answer because you so commonly want to display that thing and nobody wanted to write each widget to have a different api for each other the thousands of different types in my library.
The current system is a runtime system which has one type, and you set what the unit system is in the constructor. However it means adding a meter to a gallon is a runtime error.
Er... why would you need a different API for this? Why not just convert to unitless at the point where the number flows into the UI?
Or better yet, parametrize the UI library so that it can display any unit automatically. It could even pull the metadata (like the string for the unit) from the template, so that e.g. binding a kg<float> value to a label would automatically show as "42 kg" etc.
At the point where you convert to unitless you lose all the benefit of strong types. Which is a trade off maybe you can accept. One part of that trade off that you are adding the ability to convert to unitless and thus making it easy to use unitless where you shouldn't.
there are many different ways to implement unit systems. I know of 3 other attempts someone made on just our project to make units work before we settled on this one. There are trade offs and I don't mean to imply I have presented the correct answer for your problem. Only that because of many other reasons (not stated because of NDA) this is the best compromise for us. Your problem is different and you will need to find your own solution. There are lots of possible answers and each has a set of pros/cons. If your problems are simple than you can find an off the shelf answer, but if you need to do complex things you will need to consider what you really want.
I understand that there may be other requirements that dictate the design. It's just that the specific one that you gave originally - that of displaying the values - strikes me as something that shouldn't be difficult even when you have units reflected statically in the type system.
> At the point where you convert to unitless you lose all the benefit of strong types.
Right, but if you do that right before it actually gets displayed, then it shouldn't be a problem since all actual computations have been performed already? I mean, you also need to convert numbers to text to render them, so all the same arguments apply.
So e.g. in the "ideal" desktop app using MVVM, that would happen on the boundary between the model and the view-model.
> One part of that trade off that you are adding the ability to convert to unitless and thus making it easy to use unitless where you shouldn't.
But any typed unit-of-measure system inherently has such an ability if it tracks units properly for arithmetic operations - you just divide by 1 of the same unit to get a unitless value. E.g. in F#:
let v = 10<m/s> // in m/s
let n = v / 1<m/s> // unitless
Type checking in compile time is do-able with templates, even better with constexpr.
The problem is, of course, each library have its own set of rules and they won't interop with each other.