User-defined value type

Hello there!
Something basic today: how to write your own value type. In C# we distinguish two kinds of data type: value type and reference type. The former is a) stored on stack, b) is by default it is passed as an argument by value; the latter is a) stored on heap and only its address is stored on stack, b) is passed as an argument by reference. At this stage the important thing that is needed to know is that point a makes impact on performance [more]; point b makes impact of how data is circulating through methods. If an argument is passed by value only the value will be taken into the method and, we may say, the link between variable name and its value will be gone from method’s point of view, this means that the original variable cannot be modified by the method. If an argument is passed by reference that link will still be valid meaning that whatever changes a method do to the data it will be reflected everywhere that data is used. The code below will make it much clearer:

The output of the above would be:
As you can see modifications to our list of strings which is a reference type have been done to our object, however our integer variable which is a value type have not changed because only its value was passed to the method. That’s the main difference. The good thing to know is that value types can also be passed by reference – to do that we use keyword ref before an argument we want to pass by reference. This keyword must be present both in method signature and in its invocation place.

And the result:
So, that explanation is enough. We know what is the difference between value and reference type and what implication does that difference bring to behaviour of these types. Now, let’s move on to our custom value type. These are basically structs. They (similarly to classes) can consist of fields, properties, methods etc. and struct’s members can be static, but the struct itself cannot be static. Another important feature is that a struct cannon be derived from a class (that’s obvious) or another struct, however they can implement interfaces.

Our value type will store coordinates assuming that point 0,0 is the bottom left corner of our plane – this means that only positive values of component X and component Y can be assigned. This is due to way of how our value type will be assigned:

So, let’s start with required properties for X and Y coordinates, and distance from point 0,0. That’s simple:

Now, time for constructor. What it is actually going to do is decomposition into two coordinate component. It is also going to be private as we won’t be creating variables of this type using the constructor but simply by assigning a double.

This decomposition is achieved by using some of the static methods of Math class [see here].

Now, the fun part: how to make it possible to assign double value to our struct using ‘=’ operator? Simply by defining new implicit conversion operator that will use already defined private constructor to create an instance of our struct.

Next step would be to override three methods: ToString(), GetHashCode() and Equals() methods. A word of explanation here: although a struct is a value type it is derived from ValueType type, which in turn is derived from Object, and despite the fact that it is not necessary to override those three methods we want to be sure that they will act as we intend: ToString() will return X and Y components separated by comma, GetHashCode() will return hash code for double created based on X and Y, and Equals will check if the argument is of our user-defined type and if it does the method will compare X components and Y components:

And now we’re at the point where we could stop. Having the above done is enough to use our struct but we want to override some of the operators to make it easier to use. We will override pair ‘==’ and ‘!=’, and ‘+’ and ‘-‘ operators. For the comparison operators we assume that our structs are equal if both counterparting components are equal, for addition and subtraction we will add or subtract components X and Y:

And that’s it. Our user-defined value type is ready to use. Of course we could override more operators and I guess is-bigger-than and is-lesser-that would be a good idea but it’s easy to do so if you want to extend the struct your good to go. Below you will find complete code for all above and code for unit tests.

Regards, Michał!

Coords
Tests