Structs v classes

Structs are so important and versatile that we devote a whole chapter to them later on but it is worth saying a few words that compares and contrasts them to classes while we are on the topic.

As you might expect of a value type structs don’t support inheritance – they inherit from object but that’s the end of the inheritance hierarchy. They do support interfaces, however, more of which in the next chapter. Also a struct can have methods, properties and constructors it can’t have a destructor. Its default, i.e. parameter-less, constructor can’t be changed and always initialises all its fields to the default value of zero for a value type and to null for a reference type. You can add your own explicit constructor to initialise fields to specific values. Surprisingly although you can create a struct without the use of “new” you can write:

PointV a=new PointV();

It is important to realise that this way of creating a struct is no different from the point of view of value or reference semantics - a struct is always a value type. . There is a difference however and its that the use of new calls the struct’s default constructor which sets each field fo the struct to its default value. If you don’t use new then the fields are treated as undefined and the compiler displays an error message it you try to make use of any of the fields before they have been assigned to.

Structs are interesting for many reasons and, as mentioned initially we will return to examine them in more detail in a later chapter.

Simple Types

The simple data types, e.g. int, char, ... are clearly value types but conceptually at least they are also examples of stucts. Most of the time you can ignore this fact and just treat them as simple numbers or characters but they do have methods. For example. int is just an alias for the System.Int32 struct which inherits from object and so it has a ToString method:

int a;string b=a.ToString();

Each simple type also has methods of its own and even static methods. For example:

int I = int.MaxValue;

Of course you can’t inherit from a simple type and they have other special features such there being literals of the same type e.g. 10, 233.34 and so on.

Simple types are structs in spirit only as the compiler takes care to make sure that they are implemented in an efficient manner. Notice that as with a struct you can opt to create a simple type using the new keyword. This doesn’t have any effect other than to call the types default constructor which results in it being initialised to its default value. So for example

int I;int j;I = j;

results in a compiler error because j isn’t defined. However:

int I;int j = new int();I = j;

works perfectly because j is initialised to zero by its constructor.

Value or Reference?

You should by now understand the difference between a value and a reference type but when do you use one in preference to another?

In most cases this question is simply about using a class or a struct. The answer is nearly always that you should prefer a value type when the purpose is to store data and a reference type when some behaviour has to be implemented. What ever you choose you need to be aware of the potential for trouble that any attempt at changing a value type to a reference type can product.

For example, suppose we initially design a program using a struct:

public struct MyStruct{ public int x;}

We might very well use a method to do some computation involving a private instance of this struct:

In this example no computation is performed the struct is simply returned. Now if some other part of your program uses this method it might well go on and perform further manipulations on the returned value:

MyStruct a = doSum();a.x = 10;

In this case everything works as you would expect. The struct is treated using value semantics and the doSum returns a complete copy of the struct to create a completely separate entity in a.

This means that storing 10 in the x field doesn’t alter the value stored in MyData. Now consider the seemingly small change from a struct to a class:

the result is very different. Now the object passed as the result is treated as a reference type and subject to reference semantics. This means that doSum passes back a reference to the supposedly protected Mydata object. Now when we store 10 in the x field the its is the field in the Mydata object which is changed.

Clearly changing from a value type to a reference type and vice versa is a potentially deep structural change to a program.