why don't string object refs behave like other object refs? - c#

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

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.

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?

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 */ }

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.

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

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.

Related

Why a reference type doesn't update in C#

Here is my c# code. Why a reference type doesn't update in C#, below is the code
class Program
{
public static void Main(string[] args)
{
var a = A.field;
A.field = "2";
Console.WriteLine(a);
Console.Read();
}
}
public static class A
{
public static string field = "1";
}
The result is 1, why??
public static void Main(string[] args)
{
var a = A.field; // `a` is now a reference to the string "1"
A.field = "2"; // `A.field` is now a reference to the string "2"
Console.WriteLine(a); // nothing else has changed, so `a` is still a reference to the string "1"
Console.Read();
}
So the answer to your question is basically: the reference doesn't update, because you're not changing the reference you're writing to the Console (a), but another reference (A.field).
The behaviour you're witnessing is not limited to reference types. The same thing will happen with value types:
int x = 1;
int y = x;
x = 2; // y is still 1 at this point
This happens because the y variable stores the value 1, and changing value of x does not automatically change the value of y. x doesn't "know" about y.
It is the same with reference types - in your example a points to the same location in memory as A.field after the assignment, but it doesn't "know" where A.field points to. Therefore changing the reference of A.field doesn't influence a.
An analogy:
You give Joe a card with Cat written on it. Let Ann = Joe mean that Ann will receive a card from you with the same thing written on it as on Joe's card. So now they both have Cat written on their cards. Now if you give another card to Joe, with Dog written on it, Ann still has Cat on her card. This analogy applies to value types, for reference types you'd have a location written on the card, pointing to the place where they can find the word. The same principle still applies, though.
This is the same as following:
String a = "1";
String b = a;
b = "2";
Console.Write($"a:{a} b:{b}");
Originally you have a variable a that references the object with the content 1, and a variable b that references the same object. Then you modify the variable b to reference a new object, one with content 2. You do not modify the object referenced by a nor b, you make the variable reference a different object. You would have to modify the object referenced by b so that the a variable 'sees' the change. Alas as String is immutable there is simply no method to actually modify it. Any API at your disposal would result in a new string that b would reference, and a would look the same as before. With a mutable type you would see the difference, as long as you modify the object, not simply assign a new object to the variable:
var a = new Widget {x = 1};
var b = a;
b.x = 2;
Console.Write($"a.x: {a.x} b.x: {b.x}");
You are assigning reference and not modifying the original reference.
When you assign A.field to a you assign reference of string "1" to a. Later you assign a new string to A.field and there was no change in the original value of a. It still holds the old reference to string "1".
If somehow, you could modify the original reference then you should be able to see the change. Since your type is string, you can't really modify it because it is immutable, but consider an example with StringBuilder.
public static class A
{
public static StringBuilder field { get; set; } = new StringBuilder("1");
}
And later.
static void Main(string[] args)
{
var a = A.field;
A.field.Insert(0, "2");
Console.WriteLine(a);
Console.Read();
}
Now you will get modified value "21" in variable a as well.
Notice that the code above is modifying the field with A.field.Insert(0, "2"); and since variable a holds the reference to A.field, you see the change on the next line.
But if you try to assign a new reference to A.field with statement like:
A.field = new StringBuilder("2");
Then A.field will have a new object to reference, and the previous variable a will still keep the old reference.
You may think at a "reference" type variable as a box, where it is into an address to some resource.
Let's consider a string value.. when we assign some literal value string to a "reference", we do nothing that:
to allocate a memory area (static or heap) setted with the specified value;
to allocate another memory area (static or heap) initialized with the memory address (reference) of the string value;
When we assign a string "reference" type var to another "reference", we do nothing that to assign the memory address of the referenced string value to the new "reference".
So, if we change the first "reference" with a new assignment statement, the second will not be affected and it continues to reference the original value.
Finally, it is not possible (for now at least) have "references to references" in C#, you can have it in C++ (where pointers and references are a bit different things..). See also this Eric Lippert answer to an analougous question:
https://stackoverflow.com/a/15328414/3762855
The variable a gets a copy of value of the static property A.field.
So when you modify A.field, the copy does not change.
try this
class Program
{
static void Main(string[] args)
{
A.field = "2";
var a = A.field;
Console.WriteLine(a);
Console.Read();
}
}
public static class A
{
public static string field = "1";
}

Explanation to behavior of strings

Objects are reference types; so this code will print out Angelo.
Object o = new Object();
o.Name = "Michael";
Object p = o;
o.Name = "Angelo";
Console.WriteLine(p);
I read that string is a reference type but behaves much like a value type(like int).
int x = 10;
int y = x;
x = 20;
Console.WriteLine(y);
The code above will print 10 because y copies the actual value in the variable x. Now for the string:
string s = "Hello";
string t = s;
s = "Hi";
Console.WriteLine(t);
Now the code above for string will print "Hello". My question is this; since string is a reference type, does string s hold a reference to the object Hello when you declare it?and string t also holds a reference to that object?and the reason why Hi wasn't printed out was because of Immutability?
Or does a string when declared hold the actual value of an object much like value types?like in the second code example.
I want to have a firm grasp of the basics and I am thankful for everyones' patience with the silly questions I post here :)
Let me try to explain line by line what is going on here;
First of all, string is a reference type and reference types have 2 things. An object and a reference to that object.
string s = "Hello";
In this line, you have a "Hello" object and a reference to that object called s.
string t = s;
In this line, you have a reference called t and it refers the same object (which is "Hello") that s refers.
s = "Hi";
In this line, you create a new object called "Hi" and your s reference refers this object now. It doesn't refer the "Hello" object anymore.
Console.WriteLine(t);
Since t still refers to "Hello" object, this string will be printed. Changing the object that s refers doesn't effect it.
and the reason why Hi wasn't printed out was because of Immutability?
No, you are not doing the same thing. If you do:
Object p = o;
p = new Object();
o.Name = "Angelo";
Console.WriteLine(p);
This obviously will not affect the p. So this has nothing to do with immutability. When you assign a new reference, you are throwing away the old one.When you say:
s = "Hi";
It creates a new string object and store it's reference in s.This is default behaviour.
The only exception to this is when you use ref keyword with a reference type parameter it changes it's reference. For example:
void Foo(ref string x)
{
x = "Hi!";
}
string s = "Hello";
Foo(ref s);
// now s is 'Hi!'
Note that if you could change a property of string, you could observe the same behaviour with strings.
You can declare and initialize strings in various ways, as
// Declare without initializing.
string message1;
// Initialize to null.
string message2 = null;
// Initialize as an empty string.
// Use the Empty constant instead of the literal "".
string message3 = System.String.Empty;
The += operator creates a new string that contains the combined contents. That new object is assigned to the variable s1, and the original object that was assigned to s1 is released for garbage collection because no other variable holds a reference to it.
string s1 = "A string is more ";
string s2 = "than the sum of its chars.";
// Concatenate s1 and s2. This actually creates a new
// string object and stores it in s1, releasing the
// reference to the original object.
s1 += s2;
System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.
have a look on this link , may solve your issue;
http://msdn.microsoft.com/en-IN/library/ms228362.aspx

Is equal sign passing a reference or object copy?

When I have this code:
class A
{
public int X = 0;
...
}
public void Function()
{
// here I create a new instance of class
A a = new A();
a.X = 10;
// here I create a pointer to null
A b = null;
// here I assign a to b
b = a;
b.X = 20;
}
did I pass the reference to instance of class A now? or I cloned the instance of A to new instance and created a reference to it in b?
is changing X in b also changing X in a? Why? If not, what is a proper way to create a copy of a and insert that to b?
Why the same with strings would always create a copy? Is equal operator overridden in strings?
string a = "hello";
string b = a;
b = "world";
// "hello world"
Console.WriteLine( a + " " + b );
C# uses references not pointers. Classes are reference types.
On your example, b has the same reference with a. They referencing the same location on memory.
changing X in b also changing X in a? Why?
Yes, because they reference to the same objects and changing one reference will affect the other one.
string a = "hello";
string b = a;
b = "world";
// "hello world"
Console.WriteLine( a + " " + b );
Strings are reference types also. But they are also immutable type. Which means you can't change them. Even if you think you change them, you actually create new strings object.
line you create an object contains "hello" with a reference called a.
line you create a new reference called b referencing to the same object. ("hello")
line you assign your b reference new object called "world". Your b referance is not referencing "hello" object anymore.
did I pass the pointer to instance of class A now? or I cloned the
instance of A to new instance and created a pointer to it in b?
b is holding the same reference as a, both of them pointing to the same location.
changing X in b also changing X in a? Why?
Because both of them are pointing to the same reference.
what is a proper way to create a copy of a and insert that to b?
Implement IClonable interface
Supports cloning, which creates a new instance of a class with the
same value as an existing instance
EDIT
Since you edited the question with string, although strings are reference types but they are immutable as well
string (C# Reference)
Strings are immutable--the contents of a string object cannot be
changed after the object is created, although the syntax makes it
appear as if you can do this.
Object b is pointing to the object a, you have to do the deep clone to make a copy using IClonable Interface.
When you assign, you pass a copy of the return value of the assigned expression.
For value types, this is the value you usually get to see when you use them (like the numerical value of an integer).
For reference types, the actual value is something like an address pointing to the referenced object (but, what it really is, is an implementation detail). So, even though you pass a copy of that address, that copy points to the same object.

Make a reference to another string in C#

As far as I know a string in C# is a reference type.
So in the following code 'a' should be equal to "Hi", but it still keeps its value which is "Hello". Why?
string a = "Hello";
string b = a;
b = "Hi";
A number of the answers point out that strings are immutable; though that is true, it is completely irrelevant to your question.
What is more relevant is that you are misunderstanding how references work with respect to variables. A reference is not a reference to a variable. Think of a reference as a piece of string. You start with this:
a----------------------Hello
Then you say that "b = a", which means attach another piece of string to the same thing that a is attached to:
a----------------------Hello
/
b---------------------
Then you say "now attach b to Hi"
a----------------------Hello
b----------------------Hi
You are thinking either that references work like this:
a----------------------Hello
Then I say that b is another name for a:
a/b ----------------------Hello
Then I change b, which changes a, because they are two names for the same thing:
a/b ----------------------Hi
Or perhaps you are thinking that references work like this:
a----------------------Hello
Then I say that b refers to a:
b -------------- a ----------------------Hello
Then I change b, which indirectly changes a:
b -------------- a ----------------------Hi
That is, you are expecting to make a reference to a variable, instead of a value. You can do that in C#, like this:
void M(ref int x)
{
x = 1;
}
...
int y = 0;
M(ref y);
That means "for the duration of the call to M, x is another name for y". A change to x changes y because they are the same variable. Notice that the type of the variable need not be a reference type.
The line b = "Hi"; changes which string b references. a still references "Hello".
string a = "Hello"; // Set a to reference the string "Hello"
string b = a; // Set b to reference the same string as a
b = "Hi"; // Set b to reference the string "Hi"
You are changing the reference b. Not a. The reference itself is copied while the object remains untouched. So b = "Hi" copies a reference to the "Hi" object into b. This does not affect a.
The concept of a reference type is the most confusing thing amongst OOP programmers.
Run the below code, and you will be surprised to see the answer:
Create a simple Book class with a property called Name and write the below code in the Main method of the application.
Book a = new Book() {Name = "book a"};
Book b = new Book() {Name = "book b"};
Book c = a; //line 3
Book a = b; //Line 4
Console.WriteLine(c.Name);
And as no doubt you will expect the answer to be "book b" because of line 4. You think that as c is a and after that a became b which will also make c equals b.
Which is not the case!
Read the balloon anology at Ballon analogy for Reference type.
NO!
What you did, is to create two references ('a','b') to a string "Hello".
With b = "Hi" you change 'b' to reference the string "Hi".
'a' will never change this way.

C# assign by reference

Is it possible to assign by reference? I know that ref has to be used in methods.
string A = "abc";
string B = A;
B = "abcd";
Console.WriteLine(A); // abc
Console.WriteLine(B); // abcd
Can I have some sort of
string A = "abc";
string B = (ref)A;
B = "abcd"; // A was assigned to B as reference, so changing B is the same as changing A
Console.WriteLine(A); // abcd
Console.WriteLine(B); // abcd
That's how it works already. Strings are a reference type- your variable A is a reference (like a pointer) to a string on the heap, and you are just copying the pointer's value (the address of the string) into the variable B.
Your example doesn't change the value of A when you assign "abcd" to B because strings are treated specially in .net. They are immutable, as Kevin points out- but it is also important to note that they have value type semantics, that is assignments always result in the reference pointing to a new string, and doesn't change the value of the existing string stored in the variable.
If, instead of Strings, you used (for example) cars, and changed a property, you'd see this is the case:
public class Car {
public String Color { get; set; }
}
Car A = new Car { Color = "Red" };
Car B = A;
B.Color = "Blue";
Console.WriteLine(A.Color); // Prints "Blue"
// What you are doing with the strings in your example is the equivalent of:
Car C = A;
C = new Car { Color = "Black" };
It's probably worth noting that it does not work this way for value types (integers, doubles, floats, longs, decimals, booleans, structs, etc). Those are copied by value, unless they are boxed as an Object.
You aren't modifying the reference to A. You are creating a whole new string. A still shows "abc", because it can't be changed by modifying B. Once you modify B, it points to a whole new object. Strings are immutable too, so any change to one creates a new string.
To further answer your question with non-immutable reference types, it is possible to modify the properties of an object that a variable points to and it will show the changed effect when you access other variables pointing to the same object. This does not mean however that you can have a variable point to a brand new object, and have other variables (that pointed to the old object) point to that new object automatically without modifying them as well.
Strings are immutable that's true. However you can resolve your issue by encapsulating string within a class and making A and B instances of that class. Then A = B should work.
public class ReferenceContainer<T>
{
public T Value {get;set;}
public ReferenceContainer(T item)
{
Value = item;
}
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T (ReferenceContainer<T> item)
{
return Value;
}
}
var A = new ReferenceContainer<string>("X");
var B = A;
B.Value = "Y";
Console.WriteLine(A);// ----> Y
Console.WriteLine(B);// ----> Y
Strings are already references, after B = A then B.equals(A) will return true. However, when you do B = "abcd" you're doing the same thing, you're assigning B to a reference to the string literal.
What you are wanting to do is modify the data pointed to by the string, however, because Strings in .NET are immutable there is no way to do that.
Strings are special objects in C# because they are immutable, otherwise it would be by reference. You can run this snippet to see.
public class Foo
{
public string strA;
}
Foo A = new Foo() { strA = "abc" };
Foo B = A;
B.strA = "abcd";
Console.WriteLine(A.strA);// abcd
Console.WriteLine(B.strA);//abcd
All you do is this:
string A = "abc";
ref string B = ref A;
B = "abcd"; // A was assigned to B as reference, so changing B is the same as changing A
Console.WriteLine(A); // abcd
Console.WriteLine(B); // abcd

Categories

Resources