Deep C# - Value And Reference
Written by Mike James   
Thursday, 27 August 2015
Article Index
Deep C# - Value And Reference
Thinking About References
Arrays


coverCsharp

 

 

If you think you follow try predicting the result of (i.e. predict the values in each of the fields) the admittedly complicated:

PointV a;
a.x=1;
a.y=2

PointR b=new PointR();
b.x=3;
b.y=4;

PointV c;
PointR d;

c=a;
d=b;
c.x=5;
d.x=6;

The answer is:

a.x=1,a.y=2
b.x=6,b.y=4
c.x=5,c.y=2
d.x=6,d.y=4

because d is the same object as b but c is a new object initialised to be the same as a.

The difference between the two types of behaviour is usually expressed as value semantics versus reference semantics, i.e. is the variable the value or a reference to the value.

The advice is that structs should be used for simple data types where value assignment seems natural and classes should be used for more advanced types where reference assignment is natural. 

Arrays

The “value” semantics also has another spin-off when it comes to arrays and indeed other complex data types.

When you create an array you always use something closer to reference-type semantics as in:

int[] a=new int[10];

This creates 10 ints in a contiguous block of memory and this is very efficient.

Now consider:

PointR[] b=new PointR[10];

This creates a contiguous block of 10 reference variables of type PointR all referencing - nothing at all. That is all you have created is an array of references to null. 

To finish the array construction you have to use something like:

for(int i=0;i<b.length;i++){
 b[i]=new PointR();
}

This is, of course, not as efficient because the 10 objects are created on the heap and have to be memory managed, but all object-oriented languages suffer from this type of problem.

The good news is that C# treats arrays created using structs in the same way as simple types, i.e. using value semantics.

For example:

PointV[] c=new PointV[10];

immediately creates an array of 10 PointV objects in a contiguous block of memory.

As long as you keep thinking of value types and reference types as being more or less the same except reference types don't automatically create the object they reference you should follow and things should seem simple. 

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, but 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 it is that the use of new calls the struct’s default constructor which sets each field fof 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 structs.

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 - Decide Early Don't Change

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:

private MyStruct MyData=new MyStruct();
public MyStruct doSum()
{
 return MyData;
}

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:

public class MyClass
{
 public int x;
}

The change to the private variable and the method are easy enough:

private MyClass MyData = new MyClass();
public MyClass doSum()
{
 return MyData;
}

However if the client program performs the same manipulation:

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

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 because it changes value semantics into reference semantics. 

 

Deep C#

 front

 Chapter List

  1. Value And Reference
  2. Dynamic C#
  3. Passing Parameters
  4. Inheritance ***NEW
  5. Casting – the escape from strong typing
  6. Controlling Inheritance
  7. Delegates
  8. Multicast delegates and events
  9. Anonymous Methods, Lambdas And Closures
  10. Take Exception To Everything
  11. What's The Matter With Pointers?
  12. Generics
  13. Structs
  14. The LINQ Principle
  15. Regular Expressions in depth
  16. Bit Manipulation
  17. Async
  18. The Parallel For
Multicast delegates and events
Tuesday, 25 May 2010
Article Index
Multicast delegates and events
Events
Generic Events

Multicast delegates are useful in their own right but they also form the basis on which the C# event system is built. We take a close look at how they work and how to use them. For example, did you know you could add and subtract delegates?

 

graphics

 



 

Comments




or email your comment to: comments@i-programmer.info

 

 



Last Updated ( Wednesday, 18 November 2015 )