If a and b are both references to the same object why doesn't value of a change when we change value of b in part3. And if I assume that (as in part3) that b is dereferenced when I pass it a new literal string ,why doesn't it also dereference in part2 when I pass "foo" litaral string (ReferenceEquals returns true).
//part1
string a = "foo";
string b = a;
System.Console.WriteLine("\na = {0}\nb = {1}", a, b); //a=foo b=foo
System.Console.WriteLine("a == b : {0}", a == b);//True
System.Console.WriteLine("ReferenceEquals(a, b): {0}", ReferenceEquals(a, b));//True
//part2
b = "foo";
System.Console.WriteLine("\na = {0}\nb = {1}", a, b);//a=foo b=foo
System.Console.WriteLine("a == b : {0}", a == b);//True
System.Console.WriteLine("ReferenceEquals(a, b): {0}", ReferenceEquals(a, b));//True
//part3
b = "bar";
System.Console.WriteLine("\na = {0}\nb = {1}", a, b);//a=foo b=bar
System.Console.WriteLine("a == b : {0}", a == b);//False
System.Console.WriteLine("ReferenceEquals(a, b): {0}", ReferenceEquals(a, b));//False
a and b both refer to the same object.
However, you're changing b, not the object.
String objects are immutable and cannot be changed.
When you write b = "foo", you're changing b to refer to a different String instance.
However, string literals are interned, so writing "foo" will always give the same String instance.
You can get two different String instances with the same value by calling String.Copy:
string a = "foo";
string b = "foo";
Console.WriteLine(ReferenceEquals(a, b)); //True
b = String.Copy("foo");
Console.WriteLine(ReferenceEquals(a, b)); //False
If you change something , like a = "newstring"; it means, that 'a' points to new reference.
Strings are immutable -> you cannot change string itself (a[0] = 'b';).
In part2, when you assign some constant used previously, the reference to the old one is used. This is called 'Interning'.
If you did b = "fo" + "o";, the references wouldn't be equal (in this example they would, because compiler optimizes this, but if the string is created other way than directly used, references are the same).
var a = "foo";
var b = "fo";
b = b + "o";
// in this point, the references AREN'T equal.
b = string.Intern(b);
// in this point, the references ARE equal.
"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."
See http://msdn.microsoft.com/en-us/library/362314fe.aspx
a and b are both references to the same thing in part 1
In part 2 the references remain the same because the compiler has worked out in advance you are just reusing the same string literal (a little memory optimisation) and because strings are immutable it knows it is safe to make that optimisation.
In part 3 you are changing the reference to b only. a remains a reference to "foo" as it was before.
a and b both refer to the same object. How can a change, if you are assigning 'a' to 'b' and then changing the value of 'b'
Related
The code is pretty self explanatory. I expected when I made a1 and b1 that I was creating two different string instances that contain the same text. So I figure a1 == b1 would be true but object.ReferenceEquals(a1,b1) would be false, but it isn't. Why?
//make two seemingly different string instances
string a1 = "test";
string b1 = "test";
Console.WriteLine(object.ReferenceEquals(a1, b1)); // prints True. why?
//explicitly "recreating" b2
string a2 = "test";
string b2 = "tes";
b2 += "t";
Console.WriteLine(object.ReferenceEquals(a2, b2)); // prints False
//explicitly using new string constructor
string a3 = new string("test".ToCharArray());
string b3 = new string("test".ToCharArray());
Console.WriteLine(object.ReferenceEquals(a3, b3)); // prints False
Literal string objects are coalesced into single instances by the compiler. This is actually required by the specification:
Each string literal does not necessarily result in a new string instance. When two or more string literals that are equivalent according to the string equality operator (Section 7.9.7) appear in the same assembly, these string literals refer to the same string instance.
The compiler is optimized to that the if string literals are equal with "==" operator than it does not need to create a new instance and both refer to the same instance... So, that's why your first part of question answered True.
Although string is a reference type, the equality operators (== and !=) are defined to compare the values of string objects, not references. This makes testing for string equality more intuitive. For example:
string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine((object)a == (object)b);
This displays "True" and then "False" because the content of the strings are equivalent, but a and b do not refer to the same string instance.
The + operator concatenates strings:
string a = "good " + "morning";
This creates a string object that contains "good morning".
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. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to b. The string "h" is then eligible for garbage collection.
string b = "h";
b += "ello";
for more reference check this on msdn and this
Compiler optimization. Simple as that.
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.
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.
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
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.