5 Replies - 1003 Views - Last Post: 13 February 2013 - 04:08 PM Rate Topic: -----

#1 pharylon   User is offline

  • D.I.C Head

Reputation: 41
  • View blog
  • Posts: 86
  • Joined: 01-September 12

Why can I pass Text Boxes but not Strings?

Posted 12 February 2013 - 08:53 PM

OK, I know this is a very simple question, but bear with me.

Let's say I have a simple Winforms program that has a Form1 and a class called TextEditor. On the Winforms form is a textbox called myTextBox. When I instantiate the TextEditor class, it gets passed a reference to the myTextBox object and from there on, the TextEditor class can modify the myTextBox object as much as it wants.

So, my question is, if we substitute myString for myTextEditor, why don't changes I made to myString in the TextEditor class affect the version of myString in the Form1 class?

Or, to put it another way, why does this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            MainClass myMain = new MainClass();
            myMain.Run();
        }
    }

    class MainClass
    {
        public void Run()
        {
            string myString = "Test";
            Console.WriteLine(myString);
            Second mySecond = new Second(myString);
            mySecond.modifyString();
            Console.WriteLine(myString);
            Console.ReadKey();
        }
    }

    class Second
    {
        string myString;
        public Second(string myString)
        {
            this.myString = myString;
        }

        public void modifyString()
        {
            myString = "Test2";
        }
    }
}



write this:

Test
Test



But this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            MainClass myMain = new MainClass();
            myMain.Run();
        }
    }

    class MainClass
    {
        public void Run()
        {
            TextBox myTextBox = new TextBox();
            myTextBox.Text = "Test";
            Console.WriteLine(myTextBox.Text);
            Second mySecond = new Second(myTextBox);
            mySecond.modifyString();
            Console.WriteLine(myTextBox.Text);
            Console.ReadKey();
        }
    }

    class Second
    {
        TextBox myTextBox;
        public Second(TextBox myTextBox)
        {
            this.myTextBox = myTextBox;
        }

        public void modifyString()
        {
            myTextBox.Text = "Test2";
        }
    }
}



writes this:

Test
Test2



Strings are reference types, after all, so I don't understand why this doesn't work with strings.

This post has been edited by pharylon: 12 February 2013 - 08:57 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Why can I pass Text Boxes but not Strings?

#2 kiasta   User is offline

  • D.I.C Regular

Reputation: 30
  • View blog
  • Posts: 287
  • Joined: 18-November 07

Re: Why can I pass Text Boxes but not Strings?

Posted 12 February 2013 - 09:11 PM

replace:
string myString;
with
public string myString;
and replace
Console.WriteLine(myString);
with
Console.WriteLine(mySecond.myString);

That should do the trick:

As for the reasoning: you are calling the local variable myString instead of the class member myString. If you were intending to change the local variable you should do something like this:

myString = modifyString();

public string modifyString()
{
    string temp = "Test2";
    return temp;
}



Hope this helps :)

This post has been edited by kiasta: 12 February 2013 - 09:15 PM

Was This Post Helpful? 0
  • +
  • -

#3 pharylon   User is offline

  • D.I.C Head

Reputation: 41
  • View blog
  • Posts: 86
  • Joined: 01-September 12

Re: Why can I pass Text Boxes but not Strings?

Posted 13 February 2013 - 05:45 AM

View Postkiasta, on 12 February 2013 - 09:11 PM, said:

Hope this helps :)/>/>


Thanks for the try, but I'm not really asking how I can accomplish the same thing, I'm asking why it doesn't work. Let me try to explain what I'm confused about again, and maybe by being more detailed people might see where I'm confused.

OK, so there are two types of variables, value types and reference types. Value types live on the stack while reference types point to objects on the heap (though the reference itself is on the stack. When I mess with a value type variable, I'm messing directly with the underlying data. When I mess with a reference type, I'm not. So I get this:

        static void Main()
        {
            //Integers are value types so...
            int myInt = 1; //Create an int on the Stack with a value of 1.
            int myOtherInt = myInt; //Create a second int on the stack. Copy the same value.
            myOtherInt = 2;//Change myOtherInt to 2. Since they are value types, myInt is unaffected, so...
            Console.WriteLine(myInt); //Writes "1";


            //However, TextBoxes are reference types so....
            TextBox myTextBox = new TextBox(); //Creates a new Textbox object on the heap.
            myTextBox.Text = "myTextBox text"; //Adds to the Text property.
            TextBox myOtherTextBox = myTextBox; //Creates a new reference to SAME OBJECT on the heap.
            myOtherTextBox.Text = "myOtherTextBox text"; //Changes the text of myOtherTextBox.
            Console.WriteLine(myTextBox.Text); //Writes "myOtherTExtBox text" because it's a reference type, and both myTextBox and myOtherTextBox actually refer to the same object!!!

            //BUT!
            string myString = "Text"; //Creates a new string on the heap.
            string myOtherString = myString; //Should be creating a new reference to the same string object.
            myOtherString = "myOtherString Text"; //Alter the text...
            Console.WriteLine(myString); //Prints "Text". But WHY???? If strings are reference types, why is it acting like a value type???????


            Console.ReadKey();
        }


I just don't understand.

This post has been edited by pharylon: 13 February 2013 - 05:47 AM

Was This Post Helpful? 0
  • +
  • -

#4 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6569
  • View blog
  • Posts: 22,545
  • Joined: 05-May 12

Re: Why can I pass Text Boxes but not Strings?

Posted 13 February 2013 - 06:16 AM

It is because strings are immutable. See the section "Immutability of String Objects" in MSDN:
http://msdn.microsof...o/ms228362.aspx
Was This Post Helpful? 0
  • +
  • -

#5 pharylon   User is offline

  • D.I.C Head

Reputation: 41
  • View blog
  • Posts: 86
  • Joined: 01-September 12

Re: Why can I pass Text Boxes but not Strings?

Posted 13 February 2013 - 03:22 PM

Thanks, Skydiver. That was really helpful. Your link lead me on a little reading adventure and I learned a good bit. So, if I understand this correctly, mySecondString = myFirstSTring does not set mySecondString as a reference to the same object as myFirstString. Instead, it creates a whole new object and copies the contents of myFirstString to it. Similarly if (mySecondString == myFirstString) does not check to make sure the two references refer to the same object (as == does most of the time with references) but instead checks if the two objects contain the same data.

I went to look at the String class definition, and it seems it's operators are overloaded in such a way to make strings behave more or less like values. Interesting! I'm sure there's some reason they do that, but it's kind of confusing to me. :)/>

Also, apparently I can force a new string reference to refer to the same object as another string with the Clone() method, but it seems to me that in practice doing so is mostly pointless since they're immutable. I don't quite see why I'd ever need to do it.

This post has been edited by pharylon: 13 February 2013 - 03:26 PM

Was This Post Helpful? 0
  • +
  • -

#6 Curtis Rutland   User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 5104
  • View blog
  • Posts: 9,283
  • Joined: 08-June 10

Re: Why can I pass Text Boxes but not Strings?

Posted 13 February 2013 - 04:08 PM

*
POPULAR

Quote

So, if I understand this correctly, mySecondString = myFirstSTring does not set mySecondString as a reference to the same object as myFirstString. Instead, it creates a whole new object and copies the contents of myFirstString to it.


Incorrect. Strings are absolutely reference types, and they behave as such. String immutability is an oft-misunderstood concept. What it means is that the value that the string variable references cannot be mutated. I can reassign my string variable all day. However, I cannot actually change the value stored in memory for any particular reference.

To illustrate this concept, I can do this:

var s1 = "s1";
var s2 = "s2";
s1 = s2;


In this case, s1 and s2 both have the same memory address, they both reference a single string object.

What I cannot do is this:

var s1 = "s1";
s1[1] = '2';


I cannot modify the actual string object.

To understand that, understand that string literals each instances of strings themselves (if you want to know more on that subject, look up string interning), and when I assign s1 = "test", I'm creating an instance of a string with a value of "test", then putting the address of that string in s1. When I do s1 = s2;, I'm copying the address from s2 into s1.

This is why almost all of the methods on the string class return a string. For example, string.Replace. If strings were mutable, that would perhaps be a void method. Since strings are immutable, the operation returns a copy of the original string with the modifications applied.



Now, as to your original question, it really isn't about string immutability; it's about how reference types actually work.

You have to understand what's actually going on when you call that method. What it does is copy the pointer address from the incoming parameter to the local string variable. In the method where you update the string, it overwrites that address with a new address to a new string. What you're actually changing is where the local variable points to, not the value at the end of the original pointer.

Now, in your second example, you're passing a TextBox. The same exact thing happens. You copy the address of the TextBox from the parameter to the local instance of the TextBox. This is where the critical difference is: that reference itself contains a pointer to a string. Which you then proceed to overwrite. It's key to note you're updating a reference inside another reference. Since you're not overwriting your original reference, you're just changing a value inside of it (which happens to be another reference) the change is "propagated" back to the original. It's actually not propagated, because they're both still pointing at the same object.

Here's a diagram I drew:

Posted Image

Hopefully that helps.

If you want to see this same concept illustrated with TextBoxes, you can change your code like this. Inside modifyString, replace the code with the following:

myTextBox = new TextBox();
myTextBox.Text = "Text2"


You will see that this behaves exactly as your first example, because you're doing the exact same thing: overwriting the original reference with a new one.
Was This Post Helpful? 7
  • +
  • -

Page 1 of 1