1
string a = "a";

string b = a;

string a = "c";

Why does string b still have the value "a" and not "c"?

As string is an object and not a stack value type, what's with this behaviour?

Thanks

Pindatjuh
  • 10,550
  • 1
  • 41
  • 68
DayOne
  • 1,027
  • 1
  • 11
  • 16
  • Basically the same question: http://stackoverflow.com/questions/636932/in-c-why-is-string-a-reference-type-that-behaves-like-a-value-type – Igby Largeman May 10 '10 at 18:14

6 Answers6

27

You're pointing the variable to something new, it's no different than if you said

Foo a = new Foo();
Foo b = a;
a = new Foo();
// a no longer equal to b

In this example, b is pointing to what a initially referenced. By changing the value of a, a and b are no longer referencing the same object in memory. This is different than working with properties of a and b.

Foo a = new Foo();
Foo b = a;
a.Name = "Bar";
Console.WriteLine(b.Name);

In this case, "Bar" gets written to the screen because a and b still reference the same object.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
  • Curious that this answer is so highly upvoted, because it doesn't answer the question at all. The question is "why does string behave like a value type". – Igby Largeman May 10 '10 at 18:09
  • 3
    @Charles: Sorry, no. The OP may think this has something to do with value type semantics, but it doesn't, as this answer clearly shows. – John Saunders May 10 '10 at 18:14
  • @Charles: also, see Eric Lippert's answer below if you don't believe me. – John Saunders May 10 '10 at 18:16
  • I read Eric's answer, and while his answer and this one are both completely correct, they aren't addressing the question that the OP is asking. – Igby Largeman May 10 '10 at 18:19
  • 1
    @Charles: The OP is asking why assigning `a` in his example code to a new value doesn't also change `b`. In reality, this code would *never* change the value of `b`, regardless of type -- value type or not. So the OP is simply mistaken. – Dan Tao May 10 '10 at 18:30
  • 1
    I understand what you guys are saying, but I took his question to be asking, essentially, why his code (setting aside the obvious error) doesn't do what Anthony's second example does. Basically I felt he was equating `a = "a"` to `hypotheticalStringObj.Value = "a"`. Clearly I'm outnumbered in my interpretation, so I shall now retreat. :) – Igby Largeman May 10 '10 at 19:48
21

Let me start by saying that your choices for variables and data are poor. It makes it very difficult for someone to say "the string a in your example..." because "a" could be the content of the string, or the variable containing the reference. (And it is easily confused with the indefinite article 'a'.)

Also, your code doesn't compile because it declares variable "a" twice. You are likely to get better answers if you ask questions in a way that makes them amenable to being answered clearly.

So let's start over.

We have two variables and two string literals.

string x = "hello";
string y = x;
x = "goodbye";

Now the question is "why does y equal 'hello' and not 'goodbye'"?

Let's go back to basics. What is a variable? A variable is a storage location.

What is a value of the string type? A value of the string type is a reference to string data..

What is a variable of type string? Put it together. A variable of type string is a storage location which holds a reference to string data.

So, what is x? a storage location. What is its first value? a reference to the string data "hello".

What is y? a storage location. What is its first value? a reference to the string data "hello", same as x.

Now we change the contents of storage location x to refer to the string data "goodbye". The contents of storage location y do not change; we didn't set y.

Make sense?

why don’t string object refs behave like other object refs?

I deny the premise of the question. String object refs do behave like other object refs. Can you give an example of where they don't?

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Eric, you've really just described how value types work. You haven't said why string (a reference type) behaves like a value type, which is what the OP seems to be asking. – Igby Largeman May 10 '10 at 18:14
  • 7
    @Charles: He's explained how variables work. The OP's question really demonstrates a misunderstanding of how *variables themselves* work; replace `string` in the code in question with any other type (value type *or* reference type) -- consider the fact that under no circumstances would the code exhibit the behavior the OP seems to expect -- and you'll see that the OP is simply confused. – Dan Tao May 10 '10 at 18:25
  • 1
    @Charles: I have explained how *values* work, not how *value types* work. Remember, **the value of a variable of reference type is a reference**. I agree that it is confusing to use the word "value" twice to mean two subtly different things, but that's the situation we're in. And strings do NOT behave like value types for purposes of assignment; strings behave like value types for purposes of equality testing. The question is *not about* the equality semantics of strings which are not reference equal. – Eric Lippert May 10 '10 at 19:03
  • 1
    @Eric & others: okay, maybe I'm misinterpreting the question, so I concede. But Eric, regarding string behavior: while you are intimately familiar with the inner workings of C#/.Net, I wonder if sometimes you (and other experts here) overlook the fact that many questions from less-knowledgeable people are being asked from a more superficial perspective. That is: what is *perceived* up here on the surface, as opposed to what might really be happening deep below. My point being, strings **DO** *seem* to work exactly like value types for the purposes of assignment. Do you see what I'm getting at? – Igby Largeman May 10 '10 at 19:59
  • (continued) And I'll go a step further: not only do strings *seem* to behave like value types, for *most intents* we could get by without ever considering them to be anything other than an immutable value type. – Igby Largeman May 10 '10 at 20:00
  • 1
    @Charles: when faced with a question from a novice I attempt to answer the question by going to *first principles*. That is, stating a definition and showing how the unexpected behaviour is a direct consequence of the definition. You might be surprised at how many professional programmers cannot give a cogent explanation of the difference between a *variable* and an *object*, for example. If a developer's understanding of basic concepts is erroneous then no amount of high-level explanation is going to elicit understanding until the basic errors are cleared up. – Eric Lippert May 10 '10 at 21:12
  • @Charles: as for the question about value types: No, I don't understand your point. How do strings seem to behave as value types for the purposes of assignment? If you replaced the strings with, say, exceptions in the original queston you'd still get the same behaviour. – Eric Lippert May 10 '10 at 21:16
  • @Eric, I see what you're saying. But I believe the OP expects/assumes that there is a difference between b = a; and b = "hi";. I think he feels that the former is just like a typical object reference assignment, whereas the latter is the equivalent of dereferencing an object to access a property (say String.Value) which the compiler is conveniently doing for him. Taking your Exception example, it would be like assigning something to e.Message (let's pretend Exception.Message isn't read-only for the moment) as opposed to assigning something to e. – Igby Largeman May 10 '10 at 22:40
  • @Eric (continued), If I do e.Message = "hi"; f = e; then I know that f.Message == "hi". But with strings this doesn't happen; that's why I say strings seem to behave like value types. To put it another way, when I'm coding and I have a string called `s`, to me there is no difference between `s` and "the value of `s`". Because "the value of s" to me means the data that s refers to. But for any other reference type, I'm always mindful that SomeClass `x` refers to a *reference*, whereas `x.Foo` reaches into the instance behind that reference. I have no motivation to think of strings that way. – Igby Largeman May 10 '10 at 22:46
  • @Charles: What you are describing is a first-class concept in Visual Basic. In VB6 if you say "x = y" and x and y are both of some object type then this means "assign the default value of y to the default property of x". The reference assignment is written "Set x = y". Which is why I would go back to first principles; this concept of default values is not a concept of C#. If someone believes that it is then we should disabuse them of that notion. – Eric Lippert May 10 '10 at 23:02
  • @Eric: I think we're converging on the problem but I'm still struggling to make my point. It would be so much easier in email, so I'll contact you through your blog because I'd really like to see this discussion through to it's conclusion. :) (I will understand if you lack the time and/or inclination to respond, though) – Igby Largeman May 10 '10 at 23:31
  • @Eric: You asked me how strings seem to behave like value types. Maybe my wording was too vague. I've heard people use the phrase "value type semantics," and I suppose that's what I mean. I don't have to use `new`, and I can assign a value (data) *directly to the variable* instead of having to use a property like I do with all other ref types. (Perhaps the = operator is overloaded; all I know is what the language lets me do). And when I do s1 = s2, the result is just like it would be with integer; it's NOT like Exception. i.e. if I subsequently modify the contents of s2, s1 does not change. – Igby Largeman May 11 '10 at 15:59
3

Part of what confuses people so much about this is thinking of the following as an append operation:

str1 = str1 + str2;

If string were a mutable type, and the above were shorthand for something like this:

str1.Append(str2);

Then what you're asking would make sense.

But str1 = str1 + str2 is not just some method call on a mutable object; it is an assignment. Realizing this makes it clear that setting a = "c" in your example is no different from assigning any variable (reference type or not) to something new.

The below comparison between code that deals with two List<char> objects and code that deals with two string objects should hopefully make this clearer.

var a = new List<char>();
var b = a; // at this point, a and b refer to the same List<char>

b.Add('a'); // since a and b refer to the same List<char> ...
if (b.Contains('a')) { /* ...this is true... */ }
if (a.Contains('a')) { /* ...and so is this */ }

// HOWEVER...
a = new List<char>(); // now a and b do NOT refer to the same List<char>...
if (b.Contains('a')) { /* ...so this is still true... */ }
if (a.Contains('a')) { /* ...but this is not */ }

Compare this with a slightly modified version of the code you posted:

string a = "a";

string b = a; // at this point, a and b refer to the same string ("a")...
if (b == "a") { /* ...so this is true... */ }
if (a == "a") { /* ...and so is this */ }

// REMEMBER: the below is not simply an append operation like List<T>.Add --
// it is an ASSIGNMENT
a = a + "c"; // now they do not -- b is still "c", but a is "ac"
if (b == "a") { /* ...so this is still true... */ }
if (a == "a") { /* ...but this is not */ }
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
2

In .Net, a, b and c are reference to the objects and not the objects themselves. When you reset a, you are pointing this reference to a new memory location. The old memory location and any references to it are unchanged.

Marwan
  • 1,058
  • 1
  • 11
  • 20
0

I guess the OP thinks string objects to be mutable, so something like var = "content"; would actually store the new character array inside the already existing object.

String is, however, an immutable type, which means that in this case a new string object is created and assigned to var.

See for example: http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx

user335378
  • 33
  • 3
0

It is a misunderstanding because of the builtin string support of c#.

string a = "123"; //The way to write it in C#
string a = new string("123"); //Would be more obvious

The second way to define a is more obvious what happens, but it is verbose.Since strings have direct support from the compiler calling the string constructor is unnecessary.
Writing your example verbose:

string a = new string("a");

string b = a;

string a = new string("c");

Here the behavior is as expected a gets a reference to the new string object assigned. while the reference held by b still points to the old string.

josefx
  • 15,506
  • 6
  • 38
  • 63