Thread overview
Unexpected behavior when using both alias this and object pointer
Jan 12, 2017
xiren7
Jan 12, 2017
Ali Çehreli
Jan 13, 2017
xiren7
January 12, 2017
The problem and the code:

import std.stdio: writeln;
import core.stdc.stdlib: malloc;

struct Impl {
    ubyte[8] payload;
}

class Foo {
    Impl *impl;
    alias impl this;

    this()
    {
        impl = cast(Impl*) malloc(Impl.sizeof);
    }
}

class Foo2 {
    ubyte[8] payload;
}

void main()
{
    // alias T = Foo2;
    alias T = Foo;

    auto t = new T();

    // what I want to do is:
    // 1. cast t as pointer
    // 2. passe the pointer to a extern(C) callback function
    // 3. cast the pointer back to t in extern(C) callback function
    // 4. accesse the payload field
    auto payload = (cast(T) cast(void*) t).payload; // -> crashs

    // the right way to get the address of the t object
    writeln(*cast(void**) &t);          // -> 278E3373000

    // the unexpected behavior
    // the obvious(but wrong) way to get the address of the t object
    writeln(cast(void*) t);             // -> 278E164DAB0

    // because of alias this
    // cast(void*) t == cast(void*) t.payload
    writeln(cast(void*) t.payload);     // -> 278E164DAB0
}

My question is should let the compiler generate a warning about this unexpected(maybe) behavior?

January 12, 2017
Hiding a Foo right after Impl can be a solution. However, you need to pass 't', not '&t' to the C function because

- Although it may be unexpected, cast(void*) is the specified way of getting the address of a class object

- Taking the address of a class reference (which 't' is one), is just the address of the reference itself

So, you either have to do something similar to the following or pass void* to the C function.

import std.stdio: writeln;
import core.stdc.stdlib: malloc;

struct Impl {
    ubyte[8] payload;
}

struct ImplWithOwner {
    Impl impl;
    Foo owner;
}

class Foo {
    ImplWithOwner *io;

    Impl *payload() {
    // Guaranteed by D for structs:
    assert(cast(void*)io == cast(void*)&io.impl);
        return &io.impl;
    }

    alias payload this;

    this() {
        io = cast(ImplWithOwner*) malloc(Impl.sizeof);
        io.owner = this;
    }
}

static Foo asFoo(Impl* p) {
    return (cast(ImplWithOwner*)p).owner;
}

extern(C)
void actual_C_function(Impl* data, void function(Impl*) callback) {
    data.payload[0] = 42;
    callback(data);
}

extern(C)
void myCallback(Impl* p) {
    auto foo = p.asFoo;
    assert(foo.io.impl.payload[0] == 42);
}

void main() {
    auto t = new Foo();
    actual_C_function(t, &myCallback);
}

Ali

January 13, 2017
Thanks. Ali.
My previous post is not clear that I have to store class reference(object pointer) in void*.

My actual code is try to use libuv in D.

// genarated from uv.h, only two fields is used: 'data', 'type'.
// the document of 'data': "Space for user-defined arbitrary data. libuv does not use this field".
// uv_timer_t is the subclass of uv_handle_t in C. (uv_timer_t has all the fields defined in uv_handle_t)
struct uv_handle_t {align(8):
    union {
        struct {void* data; void* _; uv_handle_type type;}
        ubyte[96] _payload;
    }
}
struct uv_timer_t {align(8):
    union {
        struct {void* data; void* _; uv_handle_type type;}
        ubyte[160] _payload;
    }
}
...

// try to resemble the libuv object defined in C.
struct UVHandle {
    uv_handle_t _uvHandle;
    // subclass uv_handle_t
    alias _uvHandle this;

    void close() { // uv_close(&this) }
    bool isClosing() { // uv_is_closing(&this) }
    ...
}

// define Timer as 'final class', in order to force Timer allocated in gc.
final class Timer {
    UVHandle* uvHandle
    // subclass UVHandle
    alias uvHandle this;
    ...

    this()
    {
        // malloc memory(nogc) for uv_timer_t.
        uvHandle = malloc(uv_timer_t.sizeof)

        // store the timer object reference in 'data',
        // but 'alias uvHandle this' also overrides 'cast',
        // this is the problem described as my previous post.
        uvHandle.data = cast(void*) this;
    }
    ~this() { free(uvHandle); }

    void start(...) { // uv_timer_start(this.uvHandle, ...) }
    void stop() { // uv_timer_stop(this.uvHandle) }
    ...
}

My current solution is using 'mixin template' instead of 'alias this' as the way to subclass:

mixin template UVHandle() { ... }
public final class Timer {
    mixin UVHandle;
    ...
}