Hi all,

I was wondering what's the most D-idiomatic way of dealing with a C library (or rather writing wrappers for a C library) that does its own GC via reference counting. The objects are identified and passed around by integer ids only; most functions like "find me an object foo in object bar" return an id and increase a refcount internally; in rare cases, a borrowed reference is returned. Whenever refcount drops to zero, the id becomes invalid and the memory (and possibly the id as well) gets eventually reused. Some C functions may explicitly or implicitly release IDs so there's also a problem of tracking whether a live D object refers to a live C object.

Since the main concern here is wrapping the C library, the only data that is stored in D objects is the object id, so the objects are really lightweight in that sense. However, there's a logical hierarchy of objects that would be logical to reflect in D types either via inheritance or struct aliasing.

The main question here is whether it's most appropriate in this situation to use D classes and cross the fingers relying on D's GC to trigger C's GC (i.e., ~this() to explicitly decrease refcount in the C library), or use refcounted structs (or something else?). I think I understand how RefCounted works but can't see how exactly it is applicable in cases like this or what are the consequences of using it.

My initial naive guess was to use classes in D to encapsulate objects (to be able to use inheritance), so the code for the base class looks along the lines of:

class ID {
    protected int id;
    private static shared Registry registry;

this(int id) { // assume that refcount was already increased in C
        this.id = id;
registry.store(this); // store weakref to track zombie objects
    }

    ~this() @nogc {
        if (c_is_valid(id) && c_refcount(id) > 0)
            c_decref(id);
        registry.remove(this);
    }
}

class ConcreteTypeA(ID) { ... }
class ConcreteTypeB(ID) { ... }

where the weak static registry is required to keep track of live D objects that may refer to dead C objects and has to be traversed once in a while.

However there's something sketchy about doing it this way since the lifetimes of objects are not directly controlled, plus there are situations where a temporary object is only required to exist in function's scope and is naturally expected to be released upon exit from the scope.

A related thread: http://forum.dlang.org/thread/lmneclktewajznvfd...@forum.dlang.org

Reply via email to