Re: Abstract class variables question

Tech-Archive recommends: Fix windows errors by optimizing your registry



On 2007-11-19 00:49:48 -0800, "tshad" <tfs@xxxxxxxxxxxxxx> said:

[...]
StringType lastName = new StringType();
StringType email2 = new StringType();
lastName.Data = (object)dbReader["FirstName"];
email2.Data = (object)dbReader["Email2"];

At first I tried to cast them as string:
lastName.Data = (string)dbReader["FirstName"];
email2.Data = (string)dbReader["Email2"];

And that works fine, unless the value is null. In that case I get an error:

"Specified cast is not valid".

Not sure why that is since a string can be null.

Based on your later discussion of this issue, it appears to me that when you write "the value is null", it's not really null.

In spite of its name, an instance of the DBNull type is not actually a null as far as C# is concerned. It's an actual instance of an object, and in this case one that's incompatible with the String type. You can cast it to Object, because you can cast anything to Object. In fact, in the code you wrote above you don't even need the cast. You can assign anything to Object without casting.

The other thing you should be careful about is the type returned by "dbReader[]" more generally. I don't know what type that is (I do very little database work, so forgive me if it's something obvious :) ), but presumably it's always returning a specific type, and probably that type is Object. This means that when value types are returned, they are already boxed.

This doesn't really affect how you'd use it -- even if you assigned an unboxed value type to the Data property, it will be boxed for you in the conversion to Object. But I think it's a good thing to be aware of what's exactly going on.

string stemp;
stemp = null;

Works fine. So why would (string)dbReader["Email2"] not work?

Because the value being cast isn't "null", it's a reference to an instance of "DBNull".

Casting it as (object) works whether it is a null or not.

That's because "DBNull" is an instance of type Object, but it's not an instance of type String.

[...]
Once I saw that I realized I would need to change the line before call to
the ValidateType function to:

if ((value != null) && (value != DBNull.Value))
{
_ValidateType(value);
}
and that fixes that.

Well, it fixes the validation error. Whether it's really what you want to do, I'm not sure. For one, unless you change the IsNull property, you're not going to deal with value types correctly. Presumably, you'd be checking IsNull before assigning an instance of DataType, but in this case the data will be non-null (even if it's an instance of DBNull). But casting DBNull in the case of a value type will throw an exception, just like as if you'd tried to cast an actual null reference to a value type.

Personally, I would fix it by converting DBNull's to actual nulls:

if (value is DBNull)
{
value = null;
}
if (value != null)
...

(Note: I can't recall off the top of my head whether you can actually assign to the implicit "value" parameter; seems like you should be able to but if not, you can just copy it to a local variable in the setter and use that local variable instead of "value")

I also have to look at the TypedData properties also as they also give me
the Invalid Cast for it also - which if you remember is:

get { return (string)Data; }

Right. Same problem...you don't actually have a null value, you've got a reference to a DBNull instance.

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").


What I meant was that the statement creates a new reference "o" that will
point to the same location as "str" which is where the string actually is.

Well, I would say that the statement only "creates a new reference" as far as the compiler is concerned. That is, the reference variable exists in the compiled code, as a local variable. The variable itself is created as soon as you call the method containing it. Executing the assignment simply copies a reference from one variable to another. It doesn't really "create" anything.


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.

Right.

But what I was saying that it isn't the same as the string since if you
change the string in any way "another" object is created and then one of the
references would be pointing at the original string and the other reference
would be pointing at the new string.

But writing "if you change the string" isn't a precise way of describing it. You can't change a string.

Again, I realize this is a subtle point, but IMHO it's important. You may be conceptualizing the act of assigning a new string instance to your variable as "changing the string", but that's not what you're doing. You can't change a string, you can only replace a reference to one string with a reference to another. The original string remains unchanged.

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();

Right, but that is because YOU are creating a new object.

You are creating a new object in the string example as well. Granted, the object is created as part of the applicaton's pool of string constants, rather than being instantiated with the new operator. But you are still creating a new object in that case too.

In the string
case, the new object is being created because you changed the string.

You didn't change the string. The original string remains unchanged. You've simply replaced a reference to the original string with a reference to a different string.

In a
non-string object, this would not be the case. If you said B.something =
15, both A and B would still point to the same object.

But note that in that example you're not assigning to B. You're assigning to B.something. If there was an assignable "something" property on the String class, you could do the same with a String. Conversely, if you change "B.something" to "B", then assuming the assignment is legal at all (implicit conversion, casting, etc.) you would be replacing the _reference_ stored by the variable B rather than changing the original instance B referenced, just like in the string case.

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).


Right.

You are talking about a value type, I assume. Since you will have a value
type variable and a reference type variable.

No, the above discussion is entirely with respect to reference types.

[...]
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.

I was just making the point that a value type gets copied from the stack to
the heap. But if the value type is in an object and gets boxed there, it is
already on the heap (since it is part of the object) and it is actually
getting copied from the heap to another location on the heap.

Well, a couple of points here:

First, if the value type is stored in an object, that doesn't mean it's boxed. It's not. A value type is only boxed when it's _assigned_ to an object reference variable. If it's _in_ an object, it's just a plain value type.

So in that case, yes...the value when boxed is copied from one place in the heap to another. Just as if it's copied from one class instance to another would cause it to be copied from one place in the heap to another.

Looking at your statement another way, if you really do want to talk about copying an already-boxed value type to some other object reference variable, then: if a value type is already boxed, then when assigning that boxed instance to another object variable, no copying is done. Once it's a reference type, the reference can be assigned at will, with full reference type semantics. That's one of the advantages of boxing; it really does create a reference type instance that behaves just like any other reference type instance.

Boxing the value type is expensive, but once it's done, you get all of the advantages of any other reference type, including being able to assign references to other variables without having to copy all of the data.

Not really
important just that fact that a value type is not always on the stack (if it
is part of an object). That wasn't made clear in either of the articles.

I think the second article (the slides) almost got there, but yes...I'd agree neither was particularly clear on the matter.

[...]
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.

I think it is just the language here. I agree that you can't change the
string. I was just saying that if you were trying to make a change to the
string (any change) would just create another string/object with the result.
Even though it looks like the string changed - it actually didn't you are
now pointing at a new location with the changed string.

I guess my point is that long-term I think you'll have more success if you can think more literally about what's going on when you assign a new string reference to a string variable.

Don't think of it as "trying to make a change". If you were trying to make a change, you'd call some method, or assign some property, in the String class that was intended to change the instance itself. Of course, no such method or property exists on the String class; that's what makes it immutable. But you never "make a change" by assigning a reference type. The only thing that can happen when assigning a reference type is to change the reference itself.

So when you assign a string instance to a string variable, you aren't "trying to make a change" and it could lead to problems conceptualizing things later if you continue to think of the assignment as somehow different from assignments of any other reference type. Assignments of reference type variables never change the instance; you could never "make a change" to a reference type instance with a simple assignment to the reference type variable itself, and it's misleading to think of doing so with a String type variable in that way.

The important thing here is this: it's practically impossible for a human being to not be affected by the language that they use to describe things. You may tell yourself "well, I'm saying it this way, but I really mean something else". But as much as you may get away with it some of the time, for most people it's impossible to get away with it all of the time. Eventually, the way you describe the operation is going to color your perception of what's actually going on, and if you describe the operation imprecisely, your perception of what's going on will be flawed and possibly lead to problems.

What kind of problems? Well, they would possibly include just having difficulty getting a design implemented, or they could include some actual bug. Of course, bugs caused by fundamental perception problems are among the hardest to solve, because the code _looks_ fine to you.

Anyway, that's a very long way of saying I don't think you should ever think about "changing a string" in .NET. Strings are immutable and can't be changed. You also shouldn't think that assigning a reference to a string instance to a String type variable is a way to "try to change a string". It's not; it's a way to change the _reference_ to a string. It would never change the string itself, whether the class was mutable or not.

Any code you could write that _is_ actually "trying to change a string" just won't compile. Thinking that assigning a new string instance is an example of "trying to change a string" could lead to perception problems with respect to the use of the String class, or it could in fact lead to perception problems with respect to other reference types. Either way, it can lead to problems. :)

Pete

.



Relevant Pages

  • Re: Complex Specified Information - Pitman Formula
    ... Therefore a significant match between a reference and a test ... string is good evidence of non-random production. ... and there are no finite algorithms to compute their digits. ... probabilities of the different symbols the information source can produce. ...
    (talk.origins)
  • Re: String Reference Type
    ... All unary and binary operators have predefined implementations that are ... Therefore its always allocated in the heap and a variable of string ... As with all classes in this case y and x both reference the same String ... language depandant matter as below. ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Abstract class variables question
    ... 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. ... Well, that would be true for a string object too, if there was any way to actually change a string. ... 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. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Abstract class variables question
    ... Not sure why that is since a string can be null. ... But yes, in another sense a new copy of the reference is "created", ... The thing about the string class is that assigning a new string instance ... refer to that instance as being "i on the heap". ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Measurement of pitch
    ... as the method used by the Pythagoreans. ... of these reference units in the quantity to be measured. ... vibrating string seems as good as anything. ... The string or pendulum in question could no doubt be specified exactly, ...
    (sci.physics)