Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference and Value types scenario

I've been playing around trying to thoroughly understand Reference and Value types. Just when I thought I had it, I came across this scenario...

I created a class that would contain a single object.

class Container
{
    public object A {get; set;}
}

When I create an instance of this Container class (a) I am creating instance of a reference type. I assign an integer to the object within the class. As far as I am aware, this will be boxed as an object, another reference type.

int start = 1;  
Container a = new Container{ A=start };

I create another instance of the Container class (b), but assign the value of the first container to it, the value of b is now a reference to a.

Container b = a;

As expected when I print out the value of both a.A and b.A, they are the same.

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
//a.A=1,b.A=1

And, as expected, when I change the value of a.A the value of b.A also changes due to them referencing the same object.

a.A = 2;

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
// a.A=2,b.A=2

Now I decided to try this using individual local objects. Again, I box the integer into the first object and assign the value of the first object to the second. I believe the object, at this point, should be a reference type so c and d should reference the same object. Without changing anything they return the same value.

int start = 1;
object c = start;
object d = c;

Console.WriteLine("c={0},d={1}",c,d);
// c=1,d=1

Like before, when changing the value of the initial object, I expect the value of both objects to be the same.

c = 2;

Console.WriteLine("c={0},d={1}",c,d);
// c=2,d=1

When I print the result for these two objects, the value of d does not change like before.

Can someone please explain why the assignment is different in this scenario to the previous?

Thanks

like image 441
fletcher Avatar asked Dec 07 '22 02:12

fletcher


2 Answers

Here's your first mistake:

I create another instance of the Container class (b), but assign the value of the first container to it, the value of b is now a reference to a.

Container b = a;

That's not creating another instance. It's declaring another variable. Now both variables refer to the same object.

(I'll keep editing this answer as I keep reading...)

Next up:

int start = 1;
object c = start;
object d = c;
Console.WriteLine("c={0},d={1}",c,d); // c=1,d=1

Like before, when changing the value of the initial object, I expect the value of both objects to be the same.

c = 2;
Console.WriteLine("c={0},d={1}",c,d); // c=2,d=1

That's not changing an object it's changing a variable. Each of the assignments copies a value - except one of them also performs a boxing operation. Let's simplify it slightly:

object c = "first string";
object d = c;

Now there's no boxing involved - it'll just make it simpler to understand.

Both variables currently have values referring to the same object. That's due to the assignment, but there's nothing else linking the two variables. They happen to have the same value at the moment, but they're independent variables. Now let's change one:

c = "different string";

That has changed the value of c to refer to a different object. If you print out the values of c and d they will be "different string" and "first string" respectively. Changing the value of c doesn't change the value of d.


Now, let's go back to your previous scenario to see why it's different. There, you had:

a.A = 2;

That isn't changing the value of a at all. It's changing the data within the object a refers to.

Let's use a real world analogy to make this easier. Suppose all our variables are pieces of paper with house addresses written on them. The change of a.A = 2; is like changing the contents of the house at that address. Of course anyone else with the same address written on their piece of paper will see the change.

Now think of your c/d scenario. Again, imagine that we have two pieces of paper, and due to the assignment operator they both have the same address written on them. Now your assignment of a new value to the c variable itself is like scrubbing out the address on the c piece of paper and writing a different address on it. That doesn't change the d piece of paper at all - it still has the old address on, and if you visit that house, you'll see that nothing's changed. It's only what's written on the piece of paper that's changed.

Does that help?

like image 67
Jon Skeet Avatar answered Dec 30 '22 11:12

Jon Skeet


The difference is the encapsulating object Container.

In the first case you have an object that contains a reference. When you said that you created a new instance of the Container class, you didn't. You just copied the reference to the existing object. As you have two references to the same object, you can change the contents of the object via one reference and read it via the other.

 a     b          a     b
  \   /            \   /
   \ /              \ /
---------        ---------
|       |        |       |
|   A   |        |   A   |
|   |   |        |   |   |
----|----   ->   ----|----
    |                |
---------        ---------
|       |        |       |
|   1   |        |   2   |
|       |        |       |
---------        ---------

In the second case you also have two references two the same object, but in this case you reference the boxed object directly, not a container. When you assign a new value to one of the references, you get two separate objects. One object is the boxed 1, and the other object is the boxed 2. When you assign a new value to b, it will not put the value in the box that it points to, it will create a new boxed object containing the new value.

 a     b             a          b
  \   /              |          |
   \ /               |          |
---------   ->   ---------  ---------
|       |        |       |  |       |
|   1   |        |   1   |  |   2   |
|       |        |       |  |       |
---------        ---------  ---------
like image 45
Guffa Avatar answered Dec 30 '22 10:12

Guffa