www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - casting class pointer

reply Jesse Phillips <jessekphillips+D gmail.com> writes:
I usually avoid using pointers and classes together (actually I don't use
pointers very much). But using 'in' on an associative array provides a pointer.

In any case, I ended up casting the pointer to the class type. (The simplified
example isn't showing the behavior). The results were not good. I'm not sure
exactly what happened but the code is something like this:

import std.stdio;

class A { string label; /* ... */ }

class B : A {
    B[string] all; 
    string[] stuff;
}

void main() {
	 auto b = new B();
	 b.label = "Fish";//Filler
	 b.stuff ~= "Cool huh";//Filler
	 b.all["hello"] = b;//Filler

	 auto hi = "hello" in b.all;

	 auto foo = cast(B) hi;
	 foreach(s; foo.stuff) {
		writeln(s);
    }
}

The result was that b.label wasn't the same, and printing out stuff resulted in
a bunch of garbage. The questions I have are, should casting a class pointer to
a class change its behavior so it just gives you the class? Is is there a use
case for the current behavior? And should I bother working to reproduce this?

Maybe to! could be made to handle this, and upcasting?
Nov 18 2010
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, November 18, 2010 14:20:01 Jesse Phillips wrote:
 I usually avoid using pointers and classes together (actually I don't use
 pointers very much). But using 'in' on an associative array provides a
 pointer.
 
 In any case, I ended up casting the pointer to the class type. (The
 simplified example isn't showing the behavior). The results were not good.
 I'm not sure exactly what happened but the code is something like this:
 
 import std.stdio;
 
 class A { string label; /* ... */ }
 
 class B : A {
     B[string] all;
     string[] stuff;
 }
 
 void main() {
 	 auto b = new B();
 	 b.label = "Fish";//Filler
 	 b.stuff ~= "Cool huh";//Filler
 	 b.all["hello"] = b;//Filler
 
 	 auto hi = "hello" in b.all;
 
 	 auto foo = cast(B) hi;
 	 foreach(s; foo.stuff) {
 		writeln(s);
     }
 }
 
 The result was that b.label wasn't the same, and printing out stuff
 resulted in a bunch of garbage. The questions I have are, should casting a
 class pointer to a class change its behavior so it just gives you the
 class? Is is there a use case for the current behavior? And should I
 bother working to reproduce this?
 
 Maybe to! could be made to handle this, and upcasting?

Just dereference the pointer. I believe that in effect you have a pointer to a reference, not a pointer to an Object. Regardless of what it does internally though, the way to get at the object is to dereference it. If you had auto foo = *hi; then foo would be a reference to B, which is what you were trying to get. - Jonathan M Davis
Nov 18 2010
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Jonathan M Davis Wrote:

 Just dereference the pointer. I believe that in effect you have a pointer to a 
 reference, not a pointer to an Object. Regardless of what it does internally 
 though, the way to get at the object is to dereference it. If you had

The question wasn't exactly about how to get a reference to the class. The code has been evolving over time, and the cast was originally there to convert a reference of type A to type B. As I've been changing it things have become pointers and most importantly their actual type. (I've actually removed most pointers now). I just thought having cast basically do a deference/conversion wouldn't be a bad thing when casting to a class. I realize cast is supposed to be a fast operation, but if it could do the right thing too, that would be nice. Since it is there to break the type system I can't exactly ask for it to throw an Error.
Nov 18 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Jesse Phillips <jessekphillips+D gmail.com> wrote:

 	 auto hi = "hello" in b.all;

 	 auto foo = cast(B) hi;

 The result was that b.label wasn't the same, and printing out stuff  
 resulted in a bunch of garbage.

Not surprising. hi is pointing to a reference (pointer) to a B instance, not a proper B, and certainly not the one you hope for. Thus, random garbage from the memory surrounding the reference is outputted.
 The questions I have are, should casting a class pointer to a class  
 change its behavior so it just gives you the class? Is is there a use  
 case for the current behavior? And should I bother working to reproduce  
 this?

The idea behind the in operator for AAs is that it indicate whether there was something at the specified index, by returning null if there wasn't. IOW, 'a in AA' does not return a class reference, and shouldn't. You may have reasons to put nulls in your AA, in which case the returned B* may be non-null, while *hi is null. I have not thought of a good use case for this, though. However, the main reason I see is symmetry. Having to explain that for T[U] t, 'a in t' returns a T* is ok. Having to explain that this simple rule breaks when T is a class, is not good. Last, a cast is a message to the compiler of "Trust me, I know what I'm doing". That could mean that your B* is actually a B (a reference), that somehow ended up being a B*. In such a case, the only reasonable thing to do is interpreting the bits as a B instead of a B*. What you should do in the above code is auto foo = *hi; tl;dr: making the casting of class reference pointers to class references do the shortcut of interpreting the pointer as a reference is asymmetric and limits the language. -- Simen
Nov 19 2010