F# has this, I wonder how they did it?
Now, this might not necessarily be a bad thing for F# (I don't know, I'm not an F# user). The runtime type information in .NET is great, but it's all for reflection to be able to build things that a stronger type system like F# has, or a macro system, would be able to handle.
Additionally, phantom types in F# can make wrapping other types (like int -> AccountId) rather succinct.
I had gotten really close. I had types like
Base
Length: Base
Meters: Length
Feet: Length
Compound<Base, Base>
Area<T>: Compound<T, T> where T: Length
SquareMeters: Area<Meters>
SquareFeet: Area<Feet>
and had defined all of my math as generic extension methods of the Base class so that the types would compose: Compound<T, U> Multiply<T, U>(T a, U b) where T : Base where U : Base
T Divide<T, U>(Compound<T, U>, U b) where T : Base where U : Base
That went a long way towards getting fairly concrete types out of only a few lines of code. But I couldn't get it the rest of the way. C# explicitly forbids user-defined typecasts between types in an inheritance chain with each other, so while multiplying two Meters got me a Compound<Meters, Meters>, it was not then possible to take a Compound<Meter, Meter> and convert it to anything like Area<Meters> or SquareMeters automatically.Hrm, what about namespace aliasing? "using SquareMeters = Composite<Meters, Meters>"? Since the problem is not the composition of the type but the verbosity of the deeply composited types, then perhaps it's just about making a shortcut for the name.
This requires a Turing-complete type system.