digitalmars.D.learn - struct to/from void, object to/from void
- Jason King (54/54) Apr 29 2012 I'm another of what seem to be legions of people trying to interface
- Era Scarecrow (15/22) Apr 29 2012 Honestly, in my opinion, drop this. Don't make it more
- Jason King (9/20) Apr 29 2012 Since &thing works, I'm fine with it instead of opCast. The
- Era Scarecrow (26/30) Apr 29 2012 I'd say that's right and wrong. Someone correct me if I'm wrong.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (19/48) Apr 29 2012 You mean "object"? A class variable is just a handle to the class
- Era Scarecrow (27/43) Apr 29 2012 I was thinking the 'string' which was a fat pointer, but likely
- Mike Wey (6/34) Apr 30 2012 Works because a was originally created as an BA we can cast is back to
I'm another of what seem to be legions of people trying to interface with OS stores that keep void * in c/c++. My particular one is Windows TLSData, but for my example I don't need any Windows code, just D. // this based on code I snagged from this group // DMD 2.059 Win 7 Home Premium 64 bit. import std.stdio: writeln; struct MyStruct { string structName; public string toString() { return structName; } void* opCast() { return &this; } } class MyObject { string oname; this(string who) { oname = who; } public string toString() { return oname; } void* opCast() { return &this; } } void main() { MyStruct test = MyStruct("Example struct"); MyStruct test2; void* temp1 = cast(void*)test; void* temp2 = &test; assert(temp1 == temp2); writeln(*cast(MyStruct*)temp1); test2 = *cast(MyStruct*)temp1; writeln(test2); auto o1 = new MyObject("Ok"); MyObject o2; temp1 = cast(void*)o1; temp2 = &o1; //assert(temp1 == temp2); // this is true for struct, // why not object? writeln(*cast(MyObject*)temp1); o2 = *cast(MyObject*)temp1; writeln(o2); } Structs seem to go both directions just fine, although something prettier than *cast(MyStruct*) would be nice for the return trip. Objects seem to require a dedicated opCast and from my ng spelunking it appears opCast is frowned upon. How would I do the to void* w/o opCast and is there a prettier way than *cast(MyThing*) to get back the original "thing" from a void *? If I get prettier code I'll post it to the FAQ on the Wiki so that you gurus can quit dealing with the question so often.
Apr 29 2012
On Sunday, 29 April 2012 at 22:35:19 UTC, Jason King wrote:I'm another of what seem to be legions of people trying to interface with OS stores that keep void * in c/c++. My particular one is Windows TLSData, but for my example I don't need any Windows code, just D.void* opCast() { return &this; }Honestly, in my opinion, drop this. Don't make it more 'pointer-like'. Unless there's a good reason, or it makes sense (Mathematical), then don't. You keep having half the tests using regular &(address) operator; what's wrong with that? Structs having no inheritance or virtual functions hold no extra information, which is one reason you can void cast them from one type or from void to their type without any issues. Casting to an object though I am not sure, but I think it won't let you unless it is able to. Besides once you have the pointer you don't really need to deference unless you want to copy the struct. I'm not sure how safe casting an object to void* would be, or back. If you can't avoid it, I would say make overloaded methods that do the intermediate work and make it transparent for you afterwards.
Apr 29 2012
Thanks for the rapid reply.Since &thing works, I'm fine with it instead of opCast. The opCast was in the code I borrowed so I wanted to show both approaches for someone to say "this way is better" (which you did).void* opCast() { return &this; }Honestly, in my opinion, drop this. Don't make it more 'pointer-like'. Unless there's a good reason, or it makes sense (Mathematical), then don't. You keep having half the tests using regular &(address) operator; what's wrong with that?I'm not sure how safe casting an object to void* would be, or back. If you can't avoid it, I would say make overloaded methods that do the intermediate work and make it transparent for you afterwards.myobject.sizeof returns 4 (in 32 bit DMD) for every object I've tested, so I'm inclined to suspect its a bog-standard pointer, just what I'm looking to save and retrieve. Anybody else want to chime in?
Apr 29 2012
On Monday, 30 April 2012 at 00:28:15 UTC, Jason King wrote:myobject.sizeof returns 4 (in 32 bit DMD) for every object I've tested, so I'm inclined to suspect its a bog-standard pointer, just what I'm looking to save and retrieve. Anybody else want to chime in?I'd say that's right and wrong. Someone correct me if I'm wrong. The 4(bytes) is likely the fat pointer of the string. It still has to contain information saying it's this type of object, and inheritance if it was of another type. I believe it will be something like you have a 16 byte header specifying the object(s) information, and then the object data (4 bytes in this case). This is where it differs from C++ and acts more like java. A heavy part of why this is the case is not only for casting up and down, but management of virtual functions (overloaded). Otherwise you get into C++'s old mess of needing to explicitly saying virtual for every function that 'MIGHT' be overloaded in the future. I haven't tested this, but you should get the idea. class A {} class BA : A{} //returns a BA object from it's A superclass A test() { return cast(A) new BA(); //cast down } void test2() { A a = test(); BA ba = cast(BA) a; //fails if we have no information, we only see class A. assert(ba !is null, "Failed! ba not inherited from A?"); }
Apr 29 2012
On 04/29/2012 06:01 PM, Era Scarecrow wrote:On Monday, 30 April 2012 at 00:28:15 UTC, Jason King wrote:You mean "object"? A class variable is just a handle to the class object. Class variables are implemented as pointers, so yes, they will be the size of a pointer. Since I suspect that the pointers are 4 bytes on the OP's 32-bit system, I don't see any fatness there. It is just a plain pointer.myobject.sizeof returns 4 (in 32 bit DMD) for every object I've tested, so I'm inclined to suspect its a bog-standard pointer, just what I'm looking to save and retrieve. Anybody else want to chime in?I'd say that's right and wrong. Someone correct me if I'm wrong. The 4(bytes) is likely the fat pointer of the string.It still has to contain information saying it's this type of object, and inheritance if it was of another type. I believe it will be something like you have a 16 byte header specifying the object(s) information, and then the object data (4 bytes in this case). This is where it differs from C++ and acts more like java.The object itself has some data that makes it behave like its actual type but I wouldn't be surprised if it contained a virtual function table pointer just like in C++. But note that the object, not the variable is fat in that sense.A heavy part of why this is the case is not only for casting up and down, but management of virtual functions (overloaded). Otherwise you get into C++'s old mess of needing to explicitly saying virtual for every function that 'MIGHT' be overloaded in the future. I haven't tested this, but you should get the idea. class A {} class BA : A{} //returns a BA object from it's A superclass A test() { return cast(A) new BA(); //cast downCorrection: It is actually an upcast, which does not require the explicit cast anyway.} void test2() { A a = test(); BA ba = cast(BA) a; //fails if we have no information, we only seeclass A. And that's a down cast.assert(ba !is null, "Failed! ba not inherited from A?"); }I find the following message more descriptive: assert(ba !is null, "a is not actually a BA?"); To be more pedantic, 'a' is neither an A nor a BA. It is a variable that provides access to an object through the A interface. Ali
Apr 29 2012
On Monday, 30 April 2012 at 05:07:04 UTC, Ali Çehreli wrote:You mean "object"? A class variable is just a handle to the class object. Class variables are implemented as pointers, so yes, they will be the size of a pointer. Since I suspect that the pointers are 4 bytes on the OP's 32-bit system, I don't see any fatness there. It is just a plain pointer.I was thinking the 'string' which was a fat pointer, but likely I misread it and assumed the size was referring to the object's contents. 4bytes would be a single pointer, so my mistake on that part.The object itself has some data that makes it behave like its actual type but I wouldn't be surprised if it contained a virtual function table pointer just like in C++. But note that the object, not the variable is fat in that sense.But unlike in C++, it only incorporates it if you add 'virtual', so the up and down casting can revert to it's previous version. I've read about it more than used it so.. //c++ - not tested.. class Base { void func() { stdout << "base!";} } bass Derived : Base { virtual void func() {stdout << "derived (virtual)";} } void main(){ //use pointers? I can't remember... Derived d = new Derived; base b = (Base) d; b.func(); //Logically should call the derived one, but since there's no virtual table, we get the base's one instead!! } Inside the derived class it's a virtual call, change it back to it's base and it loses that extra information. You may be able to up/down cast, but it's a problem in C++. One more reason I don't use C++ if I don't have to.Correction: It is actually an upcast, which does not require the explicit cast anyway.I am getting up and down backwards. My bad..I find the following message more descriptive: assert(ba !is null, "a is not actually a BA?"); To be more pedantic, 'a' is neither an A nor a BA. It is a variable that provides access to an object through the A interface.
Apr 29 2012
On 04/30/2012 03:01 AM, Era Scarecrow wrote:On Monday, 30 April 2012 at 00:28:15 UTC, Jason King wrote:I have ;)myobject.sizeof returns 4 (in 32 bit DMD) for every object I've tested, so I'm inclined to suspect its a bog-standard pointer, just what I'm looking to save and retrieve. Anybody else want to chime in?I'd say that's right and wrong. Someone correct me if I'm wrong. The 4(bytes) is likely the fat pointer of the string. It still has to contain information saying it's this type of object, and inheritance if it was of another type. I believe it will be something like you have a 16 byte header specifying the object(s) information, and then the object data (4 bytes in this case). This is where it differs from C++ and acts more like java. A heavy part of why this is the case is not only for casting up and down, but management of virtual functions (overloaded). Otherwise you get into C++'s old mess of needing to explicitly saying virtual for every function that 'MIGHT' be overloaded in the future. I haven't tested this, but you should get the idea.class A {} class BA : A{} //returns a BA object from it's A superclass A test() { return cast(A) new BA(); //cast down } void test2() { A a = test(); BA ba = cast(BA) a; //fails if we have no information, we only see class A.Works because a was originally created as an BA we can cast is back to an BA.assert(ba !is null, "Failed! ba not inherited from A?"); }-- Mike Wey
Apr 30 2012