I'm working developing a system right now that deals with lots of conversions between semantically different values that have the same primitive .NET type (double/string/int). This means that it's possible to get confused about which 'semantic type' you are using, either by not converting or converting too many times. Ideally I'd like the compiler to issue a warning/error if I try to use a value where it doesn't semantically make sense.
Some examples to indicate what I'm referring to:
double
.Vector3D
struct.I believe F# has a compile-time solution for this (called units of measure.) I'd like to do something similar in C#, although I don't need the dimensional analysis that units of measure in F# offers.
I believe C++ could achieve this using typedef
(though I'm not a C++ expert).
The obvious solution is to wrap the double/string/whatever in a new type to give it the type information the compiler needs. I'm curious if anyone has an alternative solution. If you do think wrapping is the only/best way, then please go into some of the downsides of the pattern (and any upsides I haven't mentioned too.) I'm especially concerned about the performance of abstracted primitive numeric types on my calculations at runtime, so whatever solution I come up with must be lightweight both in terms of memory allocation and call dispatch.
I am really interested how does compiler give warning when you mix radians and degrees. Are they both double? You are in OOP world, so you should walk this way. Two suggestions:
Degree
, Radian
and define rules of conversions. Or create class 'Angle' and hold all info about units and conversions there.I guess you could create two different structs to enforce type checking. In the following code I have added an implicit cast from radians to double and an explicit cast from degress to radians. You could use whatever set of implicit and explicit operators you like, but I think the ones I have defined here would work well since the Radians struct could be passed directly into the Math
functions.
public struct Degrees
{
private double m_Value;
public static explicit operator Radians(Degrees rhs)
{
return rhs.m_Value * (Math.Pi / 180);
}
}
public struct Radians
{
private double m_Value;
public static implicit operator double(Radians rhs)
{
return rhs.m_Value;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With