What is the purpose of casting into "object" type?
Asked Answered
T

4

19

I have found code on a website which is as follows.

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);

 Console.WriteLine((object)a == (object)b); // True
 Console.WriteLine((object)a == (object)d); // True

Here, what is the purpose of casting into object type again since a,b,d are itself the objects of string?

Trailblazer answered 2/7, 2016 at 9:25 Comment(5)
Absolutely none. System.String inherits from System.ObjectLethalethal
No need to cast...Woken
The author of that code wants to call operator==(object, object) (reference equality) instead of the (better fit, as far as overload resolution is concerned) operator==(string, string) (value equality), hence the cast. Operator calls are not polymorphic, they are resolved at compile time. An alternative would be to call object.ReferenceEquals() without the casting.Elf
Subversion of the type system.Generative
That web site is missing the code that would explain what is going on; namely that if we had string e = c + c; then e and a would NOT compare equal using the "object" version, but would compare equal by just using == with no cast. That's the key point to understanding string interning: that it changes reference comparisons while keeping value comparisons the same.Guppy
T
24

The C# compiler will try to get all constant strings at compile time. This is called string interning. So after the code generated a and b are references to the same string which contains "xx".

You can check this by comparing their references (casting them to object and do the equality check or use object.ReferenceEquals). Keep in mind that == operator for strings compare their values not their references.

Another thing to mention is that strings are immutable in .NET.

string a = "xx";
string b = "x" + "x"; // String interning here
string c = string.Join("", new[] { "x", "x" }); // No interning here because it is evaluated at runtime

Console.WriteLine((object)a == (object)b); // True. Reference check
Console.WriteLine(a == b); // True. Value check

Console.WriteLine((object)a == c); //False. Reference check. Described below
Console.WriteLine(a == c); // True. Value check

So why is Console.WriteLine((object)a == c); doing a reference check?? Because the compiler will choose the == operator on object which checks for reference equality.


So the whole point of casting to object in your question is to check if string interning works or not. Assuming that there is no interning happen at compile time.

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);

Then Console.WriteLine((object)a == (object)b); would print "False", because a and b are references for two different string in memory, both of which look like "xx".

Turtle answered 2/7, 2016 at 9:28 Comment(6)
Does the interning need to be explicit when manually constructing a string? (as in the question)Venture
Operator == do value check for strings. @CarlTurtle
@dotctor But wouldn't that mean in this case, as of your explanation, reference of a equals reference b, that changing the value of b should result in changing the value of a? String is a reference type and it has a reference to an object in the Heap?Fortuna
strings are immutable in .NET. so you can not change the value of them. @FortunaTurtle
@dotctor. How does the statement Console.WriteLine((object)a == (object)b); prints true? Because here I'm not assigning a=b. Then how the reference of a and b can be equal ?Trailblazer
Compiler do it in compile time using string interning process. a is also references the same string as d because d is generated using interning process. In runtime the reference to "xx" is retrieved by using string.Intern and assigned to d so a and d are referencing to same thing.Turtle
F
6

An addition to the provided answer: string (C# Reference)

The System.String class is an immutable reference type provided in the .NET framework class library. This class creates a new string object internally for any string manipulation action. The contents of objects of this type do not change, although the syntax makes it appear as if contents can be changed. In addition, string is used as hash table key for the computation of hash values to avoid the risk of corrupting the hash data structure.

Example:

string a = "hello";
string b = "h";

// Append to contents of 'b'
b += "ello";
// When you set the variable's b value to "hello", 
// this would result in changing the pointer
// to the object in the HEAP the variable "a" is already pointing to
// Result would be: (reference of a == reference of b) --> TRUE
// b = "hello"; 

Console.WriteLine(a == b);                       // value comparison
Console.WriteLine((object)a == (object)b);       // reference comparison
Console.WriteLine (object.ReferenceEquals(a,b)); // reference comparison without casting

Result:

True
False
False

Explanation:

This will create a new object:

string a = "hello";

This will create another object:

string b = "h"; 

This will create yet another object:

b += "ello";

The following will create a reference to an existing object, more precisely, it will point to the same object the variable "a" points to → "hello".

string c = "hello"; 
Console.WriteLine (object.ReferenceEquals(a,c)); // --> TRUE

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.

Fortuna answered 2/7, 2016 at 10:57 Comment(2)
You should not mention heap or stack because these are implementation details of .NET runtime and can vary between different versions. Heap and StackTurtle
I am referring to the "Microsoft implementation of C# on the CLR". It's just an additon to your answer, to make it perhaps more understandable ;-)Fortuna
I
5

C# uses the == token to represent three distinct operators: an overloadable equality-check operator (usable on class types or value types if overloads exist for the exact types in question), a non-overloadable reference-identity-check operator (which requires that both operands be class references, and requires that the types not be mutually exclusive), and a null-check operator (which is usable with any class type, nullable value type, or generics that might be one of the above). While most forms of overloading are defined in a uniform fashion across .NET languages, the use of one operator for all three kinds of equality is not. Other languages like VB.NET use a different token for the first form (e.g. in VB.NET, the expression (x = y) uses an equality-test overload if one is defined, or generates a syntax error if not; (x Is y) tests whether x and y identify the same object instance without regard for whether an overloaded equality operator exists).

The purpose of the casts to Object is to ensure that the == token gets interpreted as representing a reference-identity-check operator rather than an overloadable equality operator; such casts are needed only because of how C implements the == operator, and would not be needed in other languages like VB.NET.

Ineslta answered 2/7, 2016 at 15:27 Comment(0)
K
1

Comment with Code

So if the values “xx” were set at runtime all to the same value of “xx” then you would get different result of false since the compiler did not have a chance to do the optimization at runtime, even though it is the same code and input values in both cases, different results for precompiled vs runtime.

private void button1_Click(object sender, EventArgs e)
{
    string a = "xx";
    string b = "xx";
    string c = "x";
    string d = String.Intern(c + c);

    Console.WriteLine((object)a == (object)b); // True
    Console.WriteLine((object)a == (object)d); // True
}

private void button2_Click(object sender, EventArgs e)
{
    string a = textBox1.Text; //type in xx at runtime
    string b = textBox2.Text; //type in xx at runtime
    string c = textBox3.Text; //type in just "x" at runtime
    string d = String.Intern(c + c);

    Console.WriteLine((object)a == (object)b); // False with runtime values that have the same value
    Console.WriteLine((object)a == (object)d); // False 
    Console.WriteLine(a == d); // True - the Equals Operator of the string works as expected still 
}
Kosher answered 2/7, 2016 at 20:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.