3

I know that String in .NET is a subclass of Object, and that Objects in .NET are reference type. Therefore, the following code puzzles me a little. Can you help me understand the difference? Thanks

I declared a class called MyInt:

class MyInt
{
    int i;

    public int number
    {
        get { return i; }
        set { i = value; }
    }

    public override string ToString()
    {
        return Convert.ToString(i);
    }
}

Then the following code:

MyInt a = new MyInt();
MyInt b = new MyInt();
a.number = 5;
b.number = 7;
b = a;
a.number = 9;

Console.WriteLine(a.ToString());
Console.WriteLine(b.ToString());

Yields:

9  
9

Which I understand because this is an Object = Reference Type and so a and b now reference the same object on the heap.

But what happens here?

 string a1;
 string b1;
 a1 = "Hello";
 b1 = "Goodbye";
 b1 = a1;
 a1 = "Wazzup?";

 Console.WriteLine(a1);
 Console.WriteLine(b1);

This yields:

Wazzup?
Hello

Is String an object who is treated differently?

svick
  • 236,525
  • 50
  • 385
  • 514
talsegal
  • 463
  • 4
  • 5
  • It's not treated differently, you just don't understand what reference type means. Try the second snippet with any other reference type, even `Object` (use the hash code to differentiate them), and you'll find the same behavior. The first would also work with any reference type, only you can't even write it in the first place with *all* immutable types (again, string isn't special). –  Aug 15 '13 at 20:48
  • 1
    [Why .NET String is immutable?](http://stackoverflow.com/questions/2365272/why-net-string-is-immutable) – I4V Aug 15 '13 at 20:53
  • I like the answer in [this question](http://stackoverflow.com/questions/1597866/c-sharp-net-string-object-is-really-by-reference?rq=1) about the same thing everyone asks when they start learning .Net – randcd Aug 15 '13 at 20:55
  • Equals is also treated different with string – paparazzo Aug 15 '13 at 20:57
  • Hi delnan, did as you asked, but still seems like it won't solve the mystery here...Added Hash codes and got the following (same hash codes..) 9 9 46104728 46104728 Wazzup? Hello 46104728 46104728 – talsegal Aug 15 '13 at 21:00
  • By "use `Object`" I meant *replace* the strings with them, like this: http://pastebin.com/w7u4wep9 –  Aug 15 '13 at 21:12

2 Answers2

6

First, we create two string variables. Right now, they reference nothing because they are not initialized:

string a1;
string b1;

Next, a string with the value "Hello" is created and a reference to that space in memory is returned. a1 is set to that reference:

a1 = "Hello"; // a1 points to a place in memory with a string containing "Hello"

Next, a string with the value "Goodbye" is created, b1 is set to reference to that.

b1 = "Goodbye";

Next we do:

b1 = a1;

This assignment will copy the value of the reference over. Now, b1 points to the string a1 points to, and "Goodbye" is unreachable. Since strings are always allocated on the heap, the garbage collector will eventually stop by and clean up the memory "Goodbye" was using, as nothing refers to it anymore.*

* Edit: Technically this probably isn't true, as string constants would be interned and thus rooted by the interned table - but let's just say these strings came from a database or something.

Next, a string with the value "Wazzup?" is created, a1 is set to a reference to that:

a1 = "Wazzup?";

The "Hello" string is still being referenced by the b1 variable, so it's safe. With all that in mind:

// Prints "Wazzup" because we just set a1 to a reference to that string
Console.WriteLine(a1);

//Prints "Hello" because b1 still has its value it had copied over from a1
Console.WriteLine(b1);

Hope this clarifies things.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • Thanks, that really clears things up. Regarding the other line of code I understood that as well, following your explanation - the reference is always kept and the number is an internal property of that object, this is why they print the same (9,9). I think I got it. Thanks again! – talsegal Aug 15 '13 at 21:16
  • Curious on the downvote. I'm *pretty sure* this is how everything works, but there's always someone with some pedantic detail I overlooked. – Mike Christensen Aug 15 '13 at 21:18
  • @user2687326 - I think you're on the right track. The thing to keep in mind is `a1` and `b1` just hold references to places in memory. Those references are copied by value upon assignment. So changing the value of `a1` does not magically change other variables that happen to point to the same thing. – Mike Christensen Aug 15 '13 at 21:22
0

Just remember that changing value of String always create new instance of String class.

For example

string test1 = "Test"; // point to memory address "1023"
test1 = "New test"; 
// Now new instance was created and variable point to another memory address
Fabio
  • 31,528
  • 4
  • 33
  • 72
  • Changing a string variable does not create an instance of String class. A string with the character sequence "New test" will be created before the program starts because that sequence appears as a string literal. The statement `test1 = "New test";` will store a reference to that pre-existing sequence into `test1`. Although `test1` will no longer refer to whatever it used to refer to, other `string` variables may continue to refer to it. – supercat Aug 15 '13 at 21:15
  • @supercat _A string with the character sequence "New test" will be created_ - sorry don't understand. If string is a `Class`, then what you mean by _creating string_? I understand it as creating instance of class(String) – Fabio Aug 16 '13 at 11:32
  • One may think of every assembly as containing a special piece of code which runs before anything else in the assembly, which says `internal String constant_strings[] = {"Test", "New Test", ...}`, which is the only thing anywhere that is allowed to define string constants. Your code above would be rendered as `test1 = constant_strings[0]; test1 = constant_strings[1];` Loading the assembly creates `constant_strings` [note that the object doesn't actually appear in any usable namespace] and all strings therein. Your code simply copies references out of the `constant_strings[]` object. – supercat Aug 16 '13 at 15:04
  • @supercat thanks, that i understand. But what happened when `test1 = "Test" + "New test". From your explaination as I understand then new string(instance) will be created from concat of `constant_strings[0]` and `constant_strings[1]`. And `test1` will refer to that new object. Isn't? – Fabio Aug 16 '13 at 16:51
  • In that particular scenario, the compiler will recognize that the concatenation of two string constants is a string constant. If the statement were instead `test1 = "Test" + test1;` the concatenation operation would generate a new string, but the assignment operator would simply store a reference to that string into `test1`. Although the statement, taken as a whole, would create a string, it would be the concatenation operator rather than the assignment which was responsible for the string's creation. – supercat Aug 16 '13 at 18:18
  • @supercat ok, but when you talking about creating a string is ti creating instance(object) of `String` class? As I understand instance of class is memory space "booked" for object's data. Variable(reference type) of class keep only memory address(pointer). If instance of class is only pointer then you right no new instance were created. But if instance of class is object itself, then new instance will be created. Of course in my example that instances created already in conastants.... – Fabio Aug 17 '13 at 09:20
  • Think of class-type variables as holding "object IDs". Suppose the system created object #57 for the string `"Test"`, and `Test1` holds "Object #24601". The expression `"Test" + test1"` will examine objects #57 and #24601, compute their combined length, and create a new string object with that length (e.g. "Object #90210") that's preloaded with their combined contents. The balance of the assignment statement will then store "Object #90210" into the variable `Test1`. Variable `Test1` won't hold the string contents, just the identifier "Object #90210". – supercat Aug 17 '13 at 18:37
  • Note that although I show object IDs as numbers for illustrative purposes, object references aren't really numbers or pointers in the usual sense. If a program creates at least e.g. 942 objects, then one and only one object will ever be the 942nd one created. There's no means in .NET of knowing which object that is, but if one assumes that some object is e.g. the 971st, it always will be the 971st. – supercat Aug 17 '13 at 18:47
  • Thanks @supercat your explanation help to certify my thoughts. – Fabio Aug 17 '13 at 19:15