3

As string is ref type in dotnet, when we update variable x, there should be update in y too ? (as it is referring value of x). sample program given below, how value of y is not changing when x is updated?

public void assignment()
{
    string x= "hello";
    string y=x; // referencing x as string is ref type in .net
    x = x.Replace('h','j');
    Console.WriteLine(x); // gives "jello" output
    Console.WriteLine(y); // gives "hello" output 
}
uvr
  • 515
  • 4
  • 12
Karan Gehlod
  • 134
  • 1
  • 9
  • 2
    No, basically. There's a difference between changing the value of a variable (which doesn't affect other variables) and changing the content of an object. See https://jonskeet.uk/csharp/references.html and https://stackoverflow.com/a/32010236/22656 – Jon Skeet Apr 28 '21 at 07:24
  • You are talking about Mutable vs Immutable. String is Immutable and it always keeps the same value. String is also Reference type and it does not have a default allocation size. – Bizhan Apr 28 '21 at 07:25
  • 3
    @Bizhan: It's not really about immutability. Even if strings were mutable, changing the value of one variable wouldn't change the other variable. (For example, suppose we were using `StringBuilder` instead of `string`, and the line in question was `x = null;` - that wouldn't make `y` null.) – Jon Skeet Apr 28 '21 at 07:29
  • @JonSkeet I think it *is* also about immutability, because e.g. `StringBuilder.Replace` mutates and returns itself, so `x = x.Replace(...)` would change the value in `y` also. – Charlieface Apr 28 '21 at 09:40
  • 1
    @Charlieface: Which is precisely why I *didn't* use `Replace` in my example. Suppose `string` were actually mutable, but `Replace` had its current behavior of returning a new string instead of modifying the existing one. (Maybe there would be a `ReplaceInExistingObject` method that would mutate it, for example.) The behavior in this question *would not change at all*. – Jon Skeet Apr 28 '21 at 09:55

3 Answers3

8

You are right that, initially, both x and y reference the same object:

       +-----------+
y   -> |   hello   |
       +-----------+
            ^
x   --------+

Now have a look at this line:

x = x.Replace('h','j');

The following happens:

  1. x.Replace creates a new string (with h replaced by j) and returns a reference to this new string.

           +-----------+    +------------+
    y   -> |   hello   |    |   jello    |
           +-----------+    +------------+
                ^
    x   --------+
    
  2. With x = ..., you assign x to this new reference. y still references the old string.

           +-----------+    +------------+
    y   -> |   hello   |    |   jello    |
           +-----------+    +------------+
                                  ^
    x   --------------------------+
    

So how do you modify a string in-place? You don't. C# does not support modifying strings in-place. Strings are deliberately designed as an immutable data structure. For a mutable string-like data structure, use StringBuilder:

var x = new System.Text.StringBuilder("hello");
var y = x;

// note that we did *not* write x = ..., we modified the value in-place
x.Replace('h','j');

// both print "jello"
Console.WriteLine(x);
Console.WriteLine(y);
Heinzi
  • 167,459
  • 57
  • 363
  • 519
3

There are already good answers here why this happens. If you however want both to print "jello" you can assign x to y by reference using the ref keyword.

string x = "hello";
ref string y = ref x;
x = x.Replace('h', 'j');
Console.WriteLine(x); // gives "jello" output
Console.WriteLine(y); // gives "jello" output 

More info on Ref locals here.

Magnus
  • 45,362
  • 8
  • 80
  • 118
  • 1
    Very good point, although I personally prefer to call it *"make y an alias for x"*, to avoid the ambiguity of the phrase "assigning by reference". – Heinzi Apr 28 '21 at 08:10
1

The string returned is a NEW string reference. In regard of string.Replace() the MSDN says:

"This method does not modify the value of the current instance. Instead, it returns a new string in which all occurrences of oldValue are replaced by newValue"

https://learn.microsoft.com/en-us/dotnet/api/system.string.replace?view=net-5.0.

As mentioned by @Heinzi - strings are immutable and most of the actions taken on strings result in new strings:

"String objects are immutable: they cannot be changed after they have been created. All of the String methods and C# operators that appear to modify a string actually return the results in a new string object"

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#:~:text=String%20objects%20are%20immutable%3A%20they,in%20a%20new%20string%20object.

Cheers!