Thread overview
nogc associative array?
Dec 27, 2014
aldanor
Dec 28, 2014
ketmar
Dec 28, 2014
ketmar
December 27, 2014
Is there a way to do something like this while keeping the destructor nogc?

class Foo {
    shared static Foo[id] registry;
    int id;
    this(int id) {
        this.id = id(
        registry[id] = this;
    }
    ~this() }. // ideally should be tagged as @nogc
         // nasty, memory corruption due to gc
        registry.remove(id)f;
        // however compiler doesn't warn about it...
    }
}
December 28, 2014
On Sat, 27 Dec 2014 23:43:54 +0000
aldanor via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
wrote:

> Is there a way to do something like this while keeping the destructor nogc?
> 
> class Foo {
>      shared static Foo[id] registry;
>      int id;
>      this(int id) {
>          this.id = id(
>          registry[id] = this;
>      }
>      ~this() }. // ideally should be tagged as @nogc
>           // nasty, memory corruption due to gc
>          registry.remove(id)f;
>          // however compiler doesn't warn about it...
>      }
> }

oh, those dtor bites... in D dtor is "object finalizer", not more. it essentially finalizes object fields that GC cannot finalize itself. please, don't use object dtors for anything else, including modifying global variables (and `registry` is a disguised global here).

besides, your dtor should never be called anyway, as the object is always anchored in `registry`. what you need here is so called "weak reference": reference to object which will not anchor it and will become `null` when GD collects an object.

D has no official weak references for now, but you can emulate weak refs, like in this code: http://repo.or.cz/w/iv.d.git/blob_plain/HEAD:/weakref.d

but please note that this code is abusing both GC/druntime internals and the fact that GC is working as it is working now. ;-)

as for your question: there is NO WAY to make GC working in dtors now. removing AA item can cause rehashing, which in turn will cause GC calls, which in turn will abort your program. it may seems to work and then BANG! it's dead.


December 28, 2014
On Sat, 27 Dec 2014 23:43:54 +0000
aldanor via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
wrote:

> Is there a way to do something like this while keeping the destructor nogc?
> 
> class Foo {
>      shared static Foo[id] registry;
>      int id;
>      this(int id) {
>          this.id = id(
>          registry[id] = this;
>      }
>      ~this() }. // ideally should be tagged as @nogc
>           // nasty, memory corruption due to gc
>          registry.remove(id)f;
>          // however compiler doesn't warn about it...
>      }
> }

p.s. what you CAN do, on the other hand, is something like this:

  shared static size_t[id] registry;

  this (int id) {
    ...
    regustry[id] = cast(size_t)cast(void*)this;
  }

  ~this () {
    auto me = (cast(size_t)cast(void*)this) in registry;
    if (me !is null) *me = 0;
  }

of course, you have to check if your object is the registry with the code like this:

  bool inRegistry (const(Foo) obj) {
    auto me = (cast(size_t)cast(void*)obj) in registry;
    return (me !is null && *me != 0);
  }

and you may consider eventual manual GC on registry by removing all 0 values from it. the easiest way to do this is to create a new AA and copy all non-zero items to it.

please note that:
1. this code assumes that GC is not compacting (it's true for now, but
can be changed in future).
2. trick with `cast(size_t)cast(void*)` is unsafe: class can override
cast operation. you can use slightly safer and uglier code instead:

  auto ptr = cast(size_t)*(cast(void**)&obj);

let the readers of your code to think a little what multiplication
operation for `cast(size_t)` mean. ;-)