Hello, in this episode I'd like to talk about the difference between reference types, and
Right at the beginning of this series, I introduced the builtin variable types, such as ints,
floats, strings, and bools. Using these, we can then also create our own
datatypes. For example, if we wanted a way to easily store a point in 2D space, we could
create a custom datatype containing a float x, and a float y.
We'd need a container for these two variables, so that they're stored together, and for that
we have two options: a class, or a struct.
Let's look at the class first. So we would create a class called Point, with our two
float variables inside. We would then have a constructor so that we can set the x and
y values when we create a new point.
Now elsewhere in our code, in some method, let's say we create a new Point 'a', with
coordinates (2,5). Roughly what happens when we do this, is a new object is created in
the computers memory, storing the x and y values. Our variable 'a' then stores a reference
to that location in memory. This is why classes are reference types.
Let's look at the implications of this. If we create a new Point 'b', and set it equal
to pointA, then both variables now refer to the same location in memory. Thus, if we were
to set b.x = 10, that value would be updated over here, and so both point a and point b
would now have an x coordinate of 10.
What if I now write b = new Point(10,5). Well in that case, a new object will be created
in the computers memory, and now point b refers to that instead. Changing the coordinates
of b will now longer affect point a, and vice versa.
Currently, both points have exactly the same coordinates, so what would happen if I created
a bool, called pointsAreTheSame, to store whether or not point a equals point b. Would
that variable be true, or false?
Well, with reference types, the values don't matter, what matters is whether or not the
variables are referring to the same location in memory, and currently they are not, so
the bool will be false.
Alright, for the next experiment lets create a void method called MovePointOneUnitRight.
The method takes one argument - a point c - and simply adds 1 to its x coordinate.
If we now call this method, passing in point b, then the variable 'c' inside the method
will refer to the same location in memory as b, and will increase its x value to 11.
Now lets change the method to instead create a new Point, with coordinates(c.x+1,c.y).
So now we're creating a new Point object in memory, which only the variable c references.
In this case of course, b's x coordinate does not change after calling the method, it remains
Now I would like to take this opportunity to introduce the 'ref' keyword. If we add
ref both before the parameter in our method call, and before the argument in the method
signature, what happens now is that any modification to the variable 'c' inside the method, will
also be made to the variable 'b' outside the method. So in this case, c gets set to a new
object, and so point 'b' will also now reference this new object.
The 'ref' keyword has one requirement, which is that the variable being passed into the
method must already have been initialized. In other words, it must already have a value.
There is another keyword 'out', which does the same thing as 'ref', but does not require
the variable to have been initialized. We'll see an example of this in the next episode.
Alright, so you should now have a good idea of how reference types behave in different
Let's now make our Point datatype into a struct, instead of a class. Structs are value types,
so let's how its behaviour differs. We'll make a point 'a' once again, and set
it equal to 2,5. This time, instead of 'a' storing the address of some location in memory,
it simply stores the x and y values itself.
So now, when we create Point b and set this equal to point a, the values from point a
are copied over into point b. Since each variable is always storing its
own copy of the values, changing one valuetype variable will not affect another. So in actual
fact, there's no difference between setting b = a, and simply creating a new point with
the same values as a.
Let's create the pointsAreTheSame bool again. The Equals method works differnently for value
types than for reference types. Here it compares the actual values of each element inside the
structs to determine whether or not the two variables are equal. Here, Points a and b
currently have the same values, and so our bool will be true.
Now using the same method example of movePointOneUnitRight, it doesn't matter what we do inside the method,
we won't be able to affect the original variable, unless we use the ref or out keywords, in
which case, just like with reference types, any modifications to the variable inside the
method, will also modify the original varialble outside the method.
So that hopefully gives you a good idea of how value types behave.
The last thing I want to mention is how the builtin types fit into this. So just about
all of the built-in types are in fact structs, making them value types. One exception to
this is "object", which we're going to ignore for now, and the other is the string class.
A string IS a reference type, but it turns out that it behaves like a value type anyway.
The reasons for this are interesting and good to know, but I'm going to gloss over them
for the time being. For now you just need to remember the following few things:
classes are references types, and thus multiple variables can all reference and affect the
same object. structs are value types, and thus each variable
contains its own copy of the values. The 'ref' and 'out' keywords can be used to
force any modification made to the variable inside the method, to also affect the original
variable outside the method. "Ref" requires the variable to
already be initialized before entering the method, while "out" does not.
Finally, the builtin datatypes such as integers, floats, chars, and bools are all value types,
and string is reference type which nevertheless behaves like a value type.