Thread overview
Problem with casting instance reference to void* and back.
Jul 27, 2015
Vlad Leberstein
Jul 27, 2015
anonymous
Jul 27, 2015
anonymous
Jul 27, 2015
Artur Skawina
Jul 27, 2015
Vlad Leberstein
July 27, 2015
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!
July 27, 2015
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;
}
---
July 27, 2015
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();
}


July 27, 2015
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
July 27, 2015
>     auto self = cast(TestInterface)cast(Object) rawSelf
Works like a charm! Thank you both!