0

In this fiddle, we are assigning a static field to an instance field. When we change the static one, the instance one still has the initial value. Why is that? We thought that both should be referring to the same object but it seems that they're not.

using System;

public class Program
{
    public static string StaticString;
    public string InstanceString;

    public static void Main()
    {
        Program.StaticString = "foo";

        var p = new Program();
        p.InstanceString = Program.StaticString;

        Program.StaticString = "bar";

        Console.WriteLine(p.InstanceString);
    }
}

We were really expecting this to print bar but it printed foo.

Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467

5 Answers5

6

In this fiddle, we are assigning a static field to an instance field.

Right. That copies the current value of the static field to the instance field. It doesn't tie the variables together forever - it just copies the current value.

When we change the static one, the instance one still has the initial value.

Yes, because you've just changed the value of the static field - why would that change the value of the instance field? They're independent variables - they just happened to hold the same value at one point. Importantly, you haven't made any change to the string object that the value of the instance field refers to. (And indeed you can't make changes to the string object, because strings are immutable.)

I view variables as being like pieces of paper with the values written on them. When the variable is a reference type, the value on the piece of paper is just a way of navigating to an object - like a street address. But copying one variable to another is always just a matter of copying what's written on one piece of paper onto another. So for example, suppose I have:

House x = new House();
House y = x;
x.DoorColor = Black;
x = null;
Console.WriteLine(y.DoorColor);

That's like:

  • Creating a piece of paper called x, and writing a street address on it
  • Copying what's written on piece of paper x onto a piece of paper called y
  • Going to the house whose address is written on piece of paper x and painting the door black
  • Rubbing out the address written on piece of paper x
  • Going to the house whose address is written on piece of paper y and reporting the colour of the door

That last step would report that the door is black, right? Rubbing out the value written on piece of paper x doesn't change either what's written on piece of paper y, or anything about the house.

This isn't quite the same set of steps as in your code, but hopefully it will shed more light on it...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Aren't we passing the reference by value? Shouldn't there be a single object at which both are pointing? – Shaun Luttin Apr 21 '15 at 05:55
  • 2
    @ShaunLuttin: Yes, we are. We're copying the value (which is a reference) from the static field to the instance field. But that's all - it's just copying that value. You're then giving a different value to the static field - that doesn't change the value in the instance field. See my edit for a longer example. – Jon Skeet Apr 21 '15 at 05:59
  • "...why would that change the value of the instance field?" I (mistakenly?) thought that strings were objects and that both variables pointed at the same object, so that if we changed the value of the one, we were changing the object at which both point. – Shaun Luttin Apr 21 '15 at 06:00
  • 1
    @ShaunLuttin: Strings *are* objects - and originally both variables *do* refer to the same object. But that just means that if you somehow make a change to the object "via" one variable, it will be seen in the other variable. But that's not what you're doing here - you're just changing the value of the static field to refer to some completely different object. You need to be very clear about the difference between "change the value of a variable" and "make a change within the object that a variable's value refers to". – Jon Skeet Apr 21 '15 at 06:01
  • Aha. I think I have it now. If I were to change the string object in some way, rather than to assign an entirely different object to the variable, then the references would still be the same (except that its a string, and strings are immutable). Thank you. – Shaun Luttin Apr 21 '15 at 06:03
  • 2
    @ShaunLuttin: Exactly. You might want to try changing your code to use `StringBuilder`, and instead of using `Program.StaticString = "bar"`, use `Program.StaticString.Append("bar")`... – Jon Skeet Apr 21 '15 at 06:05
2

When you assign StaticString to instance string in the statement below

p.InstanceString = Program.StaticString;

The runtime will actually point InstanceString to the string "foo" not to StaticString so when you assign StaticString value bar, runtime will create a string "bar" and point the static string to it. Note Instance string is still point to memory location where we have foo.

I think it will be more easy to understand with the help of a diagram. That shows how StaticString and InstanceString are actually point to values.

enter image description here

Adil
  • 146,340
  • 25
  • 209
  • 204
1

You print p.InstanceStringwhich two lines before you set to foo. So it should print foo as it does.

DrKoch
  • 9,556
  • 2
  • 34
  • 43
0

I confused changing the value of a variable with mutating the object at which a reference points.

The fact that strings are immutable of course complicates matters. b = "foo" is really the same as b = new string("foo".ToCharArray()). We're creating a new object and assigning its reference to b. We are not mutating the existing object.

Here is an example that clarifies my mistake.

using System;
using System.Text;

public class Program
{
    public static StringBuilder StaticString;
    public StringBuilder InstanceString;

    public static void Main()
    {
        Program.StaticString = new StringBuilder("foo");

        var p = new Program();
        p.InstanceString = Program.StaticString;

        Console.WriteLine("Mutating the object at which a value points:");
        Program.StaticString.Append("bar");
        Console.WriteLine(p.InstanceString);
        Console.WriteLine(Program.StaticString);

        Console.WriteLine("\nChanging the value of a variable:");
        Program.StaticString = new StringBuilder("raboof");
        Console.WriteLine(p.InstanceString);
        Console.WriteLine(Program.StaticString);
    }
}

Output

Mutating the object at which a value points:
foobar
foobar

Changing the value of a variable:
foobar
raboof
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
-2

Part of the explanation is that static members belong to the Type not to the instantiation of an object. The property referenced in the Console.WriteLine() is the instance property. But the property that was changed was the Type's property.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members#:~:text=It%20belongs%20to%20the%20type%2C%20not%20to%20instances%20of%20the%20type.

Clinton Avery
  • 167
  • 1
  • 6