Lets suppose we have only metres and seconds and only + - * and / and we're only using real. Excuse my incorrect Chapel too please. I'll just use pseudo code. The dimensions are encoded in a pair of compile time integers and the formulas for + and - require equality and for * do addition and for / subtraction of the dimensions. Now you write:
var dist = (2.0, (1,0)); var time = (4.0, (1,1));
var speed = dist / time;
and we expect the result to be (0.4,(1,-1)), which is metres/second. And if we write
dist + time
we expect a compile time error because the dimensions have to be equal for addition.
It is clear this cannot be done with a class "dimension" whose values are the pairs shown above, at best that would allow a run time check which is completely unacceptable because a formula in a loop would be pointlessly checked every iteration. So instead the pairs shown have to be types. And I mean, each and every combination of integers must be a distinct type. So metres, seconds, metres * metres, metres/seconds etc etc are all distinct types.
In C++ we could make these types:
template<int d, int t> dim;
using metres = dim<1,0>;
using seconds = dim<0,1>;
using m_per_s = dim<1,-1>;
and now, you could use template metaprogramming to do the required maths. Now you can overload + - * and / to do both real arithmetic at run time and type calculations at compile time. For example an overloaded + is easy, the types of the dimensioned real numbers just have to agree. For * the type of the result is the product of the reals and the sum of the dimensions.
So the point is, you need parametric polymorphism to represent the dimensions, and you need to be able to do the equivalent of template metaprogramming to do the type calculations. After that, it is not so hard, just messy, to overload EVERY mathematical formula in the whole system to have dimensions.
BTW: "dimensions" is a bad name too because that applies to array extents.