Thread overview
Something wrong with reflection inside struct destructor
Mar 14, 2017
Jack Applegame
Mar 14, 2017
Jack Applegame
Mar 14, 2017
Jack Applegame
Mar 14, 2017
John Colvin
Mar 14, 2017
Jack Applegame
March 14, 2017
I'm trying to write reference counted dynamic array and encountered a trouble with compile time reflection at recursive template instantiation.

for dynamic arrays (and AA too) it is normal to use recursive declarations:

struct S {
    S[] arr;
}

struct S {
    Array!S arr;
}

Look at this code: (DPaste - https://dpaste.dzfl.pl/2010191369fe)
import std.string : format;

struct Bar(E) {
    void fun() {
        pragma(msg, format("fun:   Foo.__xdtor - %s", __traits(hasMember, E, "__xdtor")));
        pragma(msg, format("fun:   Bar.__xdtor - %s", __traits(hasMember, Bar, "__xdtor")));
        pragma(msg, format("fun:   Foo.__dtor - %s", __traits(hasMember, E, "__dtor")));
        pragma(msg, format("fun:   Bar.__dtor - %s", __traits(hasMember, Bar, "__dtor")));
    }
    ~this() {
        pragma(msg, format("~this:   Foo.__xdtor - %s", __traits(hasMember, E, "__xdtor")));
        pragma(msg, format("~this:   Bar.__xdtor - %s", __traits(hasMember, Bar, "__xdtor")));
        pragma(msg, format("~this:   Foo.__dtor - %s", __traits(hasMember, E, "__dtor")));
        pragma(msg, format("~this:   Bar.__dtor - %s", __traits(hasMember, Bar, "__dtor")));
    }
}

struct Foo {
    Bar!Foo foo;
    ~this() {}
}

void main() {}

Output:
~this: Foo.__dtor - true        <--- Foo has __dtor, OK,
~this: Bar.__dtor - true
~this: Foo.__xdtor - false      <--- but hasn't __xdtor. WAT???
~this: Bar.__xdtor - true
fun: Foo.__dtor - true
fun: Bar.__dtor - true
fun: Foo.__xdtor - true
fun: Bar.__xdtor - true

Global object.destroy(ref T) function detects destructor presence by __traits(hasMember, T, "__xdtor") (https://github.com/dlang/druntime/blob/v2.073.2/src/object.d#L2440) and does nothing in such cases.

Workaround:
Avoid reflection in the destructor. Do reflection in normal function and then call it from destructor.

But it looks weird and should be fixed.

Also see related topic: https://forum.dlang.org/thread/okbzqkjijuwvmvstjnzk@forum.dlang.org
March 14, 2017
On Tuesday, 14 March 2017 at 12:44:16 UTC, Jack Applegame wrote:
> Workaround:
> Avoid reflection in the destructor. Do reflection in normal function and then call it from destructor.

This doesn't work - https://dpaste.dzfl.pl/5a1d93f7a277
Call from destructor changes compiler behavior. This is terrible.


March 14, 2017
This is completely unacceptable:

DPaste(https://dpaste.dzfl.pl/f54f578c4ec9)

import std.stdio;
import std.string;
import std.experimental.allocator;
import std.experimental.allocator.mallocator : Mallocator;

struct Bar(E) {
    E* ptr = null;
    void allocate(int m) { ptr = Mallocator.instance.make!Foo(m); }
    ~this() {
        if(ptr !is null) Mallocator.instance.dispose(ptr);
    }
}

struct A {
    int m;
    ~this() { writefln("A.~this(%s)", m); }
}

struct Foo {
    A a;
    Bar!Foo bar;
    this(int m) { a = A(m); }
}

void main() {
    auto foo = Foo(1);
    foo.bar.allocate(10);
}

Output:
A.~this(1)

Expected output:
A.~this(10)
A.~this(1)

Can someone to fix this ASAP for $100?
March 14, 2017
On Tuesday, 14 March 2017 at 13:38:52 UTC, Jack Applegame wrote:
> On Tuesday, 14 March 2017 at 12:44:16 UTC, Jack Applegame wrote:
>> Workaround:
>> Avoid reflection in the destructor. Do reflection in normal function and then call it from destructor.
>
> This doesn't work - https://dpaste.dzfl.pl/5a1d93f7a277
> Call from destructor changes compiler behavior. This is terrible.

bug report?
March 14, 2017
On Tuesday, 14 March 2017 at 14:33:49 UTC, John Colvin wrote:
> bug report?
https://issues.dlang.org/show_bug.cgi?id=17257