Re: Abstract class variables question
- From: Peter Duniho <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Sun, 18 Nov 2007 19:51:19 -0800
On 2007-11-18 12:55:03 -0800, "tshad" <tfs@xxxxxxxxxxxxxx> said:
I think I understand boxing a little better now.
After reading your information and a couple of other articles - I think I
have a better idea what it is and why it is used. The problem was the WHY.
I had seen other articles on the HOW but not much on the why:
int i,j;
object o = i; // Boxed
j = (object) o/ // unboxed.
This shows how it is done but not why you would use it.
Has the "why" been adequately explained yet? Or would you like elaboration on that?
You're right in that I didn't understand the string type not being boxed and
the values being boxed and why they were different. But now if I understand
it correctly:
1) value types are stored on the stack (faster)
Value types are stored on the stack when they are local variables. But as I think you've seen elsewhere in this thread, a value type can exist inside a class and in that case the value type is stored in the heap with the rest of the class instance.
But as far as the "faster" goes, yes...to some extent value types have less overhead than reference types, and so can perform better in certain cases.
2) reference types are stored on the heap and have a reference/pointer to
the object that is on the heap.
Right. That is, a reference type variable itself would still be stored on the stack if it's a local variable, but only the reference is stored on the stack. The instance itself is stored in the heap.
3) value types are copied to the heap and made into an object and reference
type (in essence) that now has a reference/pointer pointing to the new
object.
Right, that's boxing.
4) String types are already reference types and all we are doing when we do
"object o = str" is create a new reference/pointer that points to the object
on the heap.
Depends on your definition of "create". My view is that the assignment doesn't create anything. The source and destination already exist, and the reference is copied from one to the other.
But yes, in another sense a new copy of the reference is "created", replacing whatever was in the variable before (and in that sense, if the reference is "created", the previous value of the variable is "destroyed").
In the case of a non-string object, the object is the same but we have 2
pointers to that same object. If the object changes value and both
references point to the same object, they will be the same.
Well, that would be true for a string object too, if there was any way to actually change a string.
Likewise, if you assign a new reference to a reference type variable, that doesn't affect other variables that might have referenced the same object that variable previously referenced. For example:
object A = new object();
object B = A;
A = new object();
That's just like the string case. Assigning a new reference to A doesn't change what B references. This works for _any_ reference type variable.
The thing about the string class is that assigning a new string instance to a string type variable is the _only_ way to change the string value of that variable. Mutable classes, you can call some method or set a property or something like that, and that will change the instance itself, without requiring you to assign a new instance of the class to a variable.
I realize that the distinction might seem subtle, or even pedantic. But I think it's a very important distinction. In particular, it's very important to understand that with respect to the code we've seen in this thread, the string class isn't really so different from other classes. Because it's immutable, you _have_ to write code like we've seen here, while other classes might provide other options. But even with a mutable class, if you write code like we've written here, it'll behave just like the string class (except of course for the one example I showed specifically designed to change a class instance without reassiging the variable).
But in the case of a string, which is immutable, the 1st reference would
point to the first string and the 2nd reference (after the string is
changed) will point to the new string. And that would be the case, even if
we didn't move it to a new object.
Even if we didn't move what to a new object?
As far as "the string is changed", I think it's important to understand, the original string isn't changed. You create a whole new string instance, and the string type variable itself is changed to reference the new string instance.
Again, maybe it seems pedantic, but I think it's important to understand the difference between the variable referencing some data and the data itself, and along with that to make sure the language one is using is clear about that difference.
string A = "something";
string B;
B = A;
A += " Else";
gives me the same result as:
string s1 = "something";
object o1 = s1;
s1 += " Else";
Where A <> B and o1 <> s1 because in both cases a new string is created even
though we think we are changing the strings.
Well, you might think you are changing the strings. :)
Seriously though, it is practically always the case that when you are writing an assignment to a reference, you're replacing the reference held by the variable. The obvious exception is of course where for whatever reason your code sometimes assigns a reference to a variable when it already holds that reference. Another example, one that I hope is _extremely_ uncommon, would be in the case of an operator that's overloaded to return the original instance reference for one of the operands.
But as a general rule of thumb, changing an instance will go through some member of the instance, while changing a reference value will involve the assignment operator. The string class has no member of the class that allows the instance to be changed, which is what makes it immutable. But the "changing a reference value" is the same for the string class as it is for any other class, immutable or not.
I also found a better article/tutorial which I think was trying to say the
same thing as the first one but this one does it better. He isn't
addressing the string reference type but address reference types in general.
http://www.jaggersoft.com/csharp_course/13_Boxing_files/frame.htm
I think he is saying the same thing you are saying (but he also doesn't go
into the string reference type).
Yes. I didn't care for the web design very much :), but it seems like a better discussion of the concept.
[...]_objCurrent isn't on the stack, which is all I was pointing out.
I assume that _objCurrent isn't on the stack because the object is not on
the stack and all reference types are stored on the heap. But is
_objCurrent just a pointer (reference) to the actual object (on the heap).
Your assumption is correct. And yes, _objCurrent is a variable that contains a reference to the actual object on the heap.
[...]
The boxing of the variable "i" does not in any way relate the variable "i"
to something on the heap. It _copies_ the value from the variable "i"
into a completely new data structure. Once this is done, "i" is
completely irrelevant to the reference instance. It's very misleading to
refer to that instance as being "i on the heap".
It may be misleading but I think the value that gets copied does get copied
to the heap. But in the case of an Class Object that is already on the
heap, you are copying the value from a heap location to a heap location.
I think you lost me. I'm not sure what "Class Object" refers to (maybe something in the previously referenced web page?), but assuming it's a class, it's a reference type and assigning the reference to the instance to any variable just copies the reference, not the class instance itself.
If that's what you meant, then I'll agree with that. :)
[...]
The current value of "i" is passed into the constructor, where it's copied
to the private field "_value". You can read it back out, which then
copies the value from the private field to wherever you assign it. But "i"
is only relevant when the instance is first constructed, and there only as
it's passed by value to the constructor.
So in this case I have "i" which is a value Type and boxed.i (if i were
public) which are completely different even if they have the same value at
the start. If I then change "i" to 30, boxed.i will still = 5.
Exactly.
[...]In that case, your statement that "B will be 'something'" is not true. BI got it.
continues to reference the same instance as A, and having changed that
instance so that it contains "something else" instead, the instance of
Mutable that B refers to will contain "something else" (because it's the
same instance).
If the string is inside the object and A and B both pointed at the object
even if the string changed INSIDE the object, since A and B are both
pointing at the same object with the string changed and therefore A.String
and B.String would be the same.
Right.
But in the above case:
string A = "something";
object B;
B = A;
A = "Something Else"
You really do have 2 references to 2 different objects (a string and and an
object) and NOT 2 references to the same object.
Well, the _variable_ type is object for the second reference, but after the third line ("B = A") you still only have one object: the original string ("something").
Using the variable B you could only do things with the instance that are defined in the class Object. But the instance is still a string.
After the fourth line, you now have two objects, both of them strings. The original string is now only accessible via a variable typed as Object, so you can only use the things defined in the Object type. But you could cast the reference held in B back to a string, and you'd then be able to do all the things the class String defines with the instance.
And because of the way a
string works when you change A you actually get a 3rd object
No, only a second object. See above.
and the
original object is dereferenced by 1 and if nothing else is referencing it,
the GC will get rid of it.
For what it's worth: there's no ref-counting in the GC. The garbage collector just scans the variables referencing data, and for any object for which it doesn't find something referencing it, it collects that object (to oversimplify the mechanism a bit :) ).
I'm not sure what you mean by "nothing else". To me, that means "nothing other than B", and if so the statement's not correct. B referencing the instance is sufficient to prevent it from being collected. If B is the only variable referencing the instance however, then once B is assigned something else, or simply goes out of scope, then yes...the original instance can be collected.
[...]Mutable A, C;I think I have it. In the above example, I think A = B = C, since all 3 are
object B;
A = new Mutable("something");
B = A;
A.String = "something else";
C = (Mutable)B;
Console.WriteLine(C.String);
[...]
reference types and point to the same object (and none are strings).
That's right.
[...]
Maybe it is different with ints and strings.
The int type and string type are _definitely_ handled differently. An int
is a value type, and so to assign an int instance to an object variable,
it has to be boxed. But a string is a reference type, and assigning a
string instance to an object variable requires no such work.
But the string is a special type of reference type (immutable) in that you
can't just assign the reference to another string and assume they will stay
the same, since any change to the string will now change the object the
reference is pointing to. Correct?
Sort of. I think I explained this above, but just to reiterate:
Knowing that the String class is immutable, you know that if two or more variables do reference the same instance, that that instance will never change.
In that respect it's not correct to write "any change to the string", since there's no such thing. A string is immutable; there can be no change to the string.
As far as an assignemnt goes, if you assign a new instance to one of the variables, none of the other variables will be affected by the assignment. But that is true for any class, whether mutable or immutable.
Having a class that's immutable gives you a certain guarantee for a given instance, and thus for multiple variables all referencing that instance. And it also places a specific requirement on how you can change the data a particular variable describes: you can only replace the reference with a new reference to a different instance, rather than modifying the instance itself.
Basically: immutable places a requirement that an assignment be used for specific kinds of behavior, but it doesn't actually affect what happens during an assignment. Assignments have the same effect for mutable classes as they do for immutable classes.
Pete
.
- Follow-Ups:
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- References:
- Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Re: Abstract class variables question
- From: Peter Duniho
- Re: Abstract class variables question
- From: tshad
- Abstract class variables question
- Prev by Date: Re: Testing File Format
- Next by Date: Re: Testing File Format
- Previous by thread: Re: Abstract class variables question
- Next by thread: Re: Abstract class variables question
- Index(es):
Relevant Pages
|