www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with casting instance reference to void* and back.

reply "Vlad Leberstein" <zeronineseven gmail.com> writes:
Hi! My use case requires interaction with C API which in turn 
implies storing object instance reference as void *. I'm using 
gdc 4.9.2 and everything worked fine with "object -> void * -> 
object" conversion, but "object -> void * -> interface" failed. 
The stripped-down example is something like this:

interface TestInterface {
     void testMethod();
}

class TestImpl : TestInterface {
     void testMethod() {
         writefln("TestImpl::testMethod\n");
     }
};

void testDispathcer(void *rawSelf) {
     auto self = cast(TestInterface) rawSelf;
     // nothing happens
     self.testMethod();
}


int main(string[] args) {
     auto t = new TestImpl();
     testDispathcer(cast(void *) t);
     return 0;
}

However this works:

void testDispathcer(TestImpl rawSelf) {
     auto self = cast(TestInterface) rawSelf;
     // TestImpl::testMethod is printed to stdout
     self.testMethod();
}


int main(string[] args) {
     auto t = new TestImpl();
     testDispathcer(t);
     return 0;
}

Is there any way to handle such situation without resorting to 
templating dispatcher with every *Impl type? As second example 
works as expected I presume that runtime loses some type 
information to perform downcast and maybe it's possible to 
extract it and store externally and merge back later?

I'm quite new to D and sorry if the question is dumb. Any help 
would be greatly appreciated! Thanks in advance!
Jul 27 2015
next sibling parent reply "anonymous" <12321 456.654> writes:
On Monday, 27 July 2015 at 12:03:06 UTC, Vlad Leberstein wrote:
 Hi! My use case requires interaction with C API which in turn 
 implies storing object instance reference as void *. I'm using 
 gdc 4.9.2 and everything worked fine with "object -> void * -> 
 object" conversion, but "object -> void * -> interface" failed. 
 The stripped-down example is something like this:

 interface TestInterface {
     void testMethod();
 }

 class TestImpl : TestInterface {
     void testMethod() {
         writefln("TestImpl::testMethod\n");
     }
 };

 void testDispathcer(void *rawSelf) {
     auto self = cast(TestInterface) rawSelf;
     // nothing happens
     self.testMethod();
 }


 int main(string[] args) {
     auto t = new TestImpl();
     testDispathcer(cast(void *) t);
     return 0;
 }

 However this works:

 void testDispathcer(TestImpl rawSelf) {
     auto self = cast(TestInterface) rawSelf;
     // TestImpl::testMethod is printed to stdout
     self.testMethod();
 }


 int main(string[] args) {
     auto t = new TestImpl();
     testDispathcer(t);
     return 0;
 }

 Is there any way to handle such situation without resorting to 
 templating dispatcher with every *Impl type? As second example 
 works as expected I presume that runtime loses some type 
 information to perform downcast and maybe it's possible to 
 extract it and store externally and merge back later?

 I'm quite new to D and sorry if the question is dumb. Any help 
 would be greatly appreciated! Thanks in advance!
In the first example, you pass a pointer to a class instance. You cannot get the vtbl entry for the interface like this. Instead try to do this in 2 steps: --- import std.stdio; interface TestInterface { void testMethod(); } class TestImpl : TestInterface { void testMethod() { writefln("TestImpl::testMethod\n"); } }; void testDispathcer(void *rawSelf) { auto obj = cast(Object) rawSelf; auto self = cast(TestInterface) obj; // nothing happens self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(cast(void *) t); return 0; } ---
Jul 27 2015
parent "anonymous" <12321 456.654> writes:
On Monday, 27 July 2015 at 13:11:33 UTC, anonymous wrote:
 In the first example, you pass a pointer to a class instance. 
 You cannot get the vtbl entry for the interface like this. 
 Instead try to do this in 2 steps:
actually i meant you pass an untyped pointer, so when you cast as interface it's not like if the vtbl of an object is queried. So you have to upcast to an Object then cast to the interface, which is not a simple cast (it get something in the virtual table. void testDispathcer(void *rawSelf) { auto obj = cast(Object) rawSelf; // reinterpret auto self = cast(TestInterface) obj; // get vtbl entry , it's not a simple cast // works self.testMethod(); }
Jul 27 2015
prev sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 07/27/15 14:03, Vlad Leberstein via Digitalmars-d-learn wrote:
 Hi! My use case requires interaction with C API which in turn implies storing
object instance reference as void *. I'm using gdc 4.9.2 and everything worked
fine with "object -> void * -> object" conversion, but "object -> void * ->
interface" failed. The stripped-down example is something like this:
 
 interface TestInterface {
     void testMethod();
 }
 
 class TestImpl : TestInterface {
     void testMethod() {
         writefln("TestImpl::testMethod\n");
     }
 };
 
 void testDispathcer(void *rawSelf) {
     auto self = cast(TestInterface) rawSelf;
     // nothing happens
     self.testMethod();
 }
 
 
 int main(string[] args) {
     auto t = new TestImpl();
     testDispathcer(cast(void *) t);
     return 0;
 }
 Is there any way to handle such situation without resorting to templating
dispatcher with every *Impl type?
auto self = cast(TestInterface)cast(Object) rawSelf [you should probably check for null, and consider using a reinterpret-cast (`testDispathcer(*cast(void **)&t)`) because a "normal" one can be overridden by the class, sometimes accidentally] artur
Jul 27 2015
parent "Vlad Leberstein" <zeronineseven gmail.com> writes:
     auto self = cast(TestInterface)cast(Object) rawSelf
Works like a charm! Thank you both!
Jul 27 2015