On Friday, 12 March 2021 at 17:37:43 UTC, David  Zhang wrote:
I want to store interfaces as untyped void[], then cast them back to the interface at a later time.

Assuming these interfaces are actual D `interface`s, declared with the keyword and using the default `extern(D)` linkage, you're way over-complicating things. All `extern(D)` `class`es are sub-types of `object.Object`, and have type information accessible through the implicit virtual function table pointer `__vptr` that can be used to perform safe dynamic casts:

////////////////////////////////////////////
/* Fully qualified names can be *very* long because of templates, so it can be wasteful to store and compare them at runtime. Let's use `TypeInfo` instead: */
Object[TypeInfo] map;

void register(I)(I i)
if(is(I == interface)) // This wouldn't work right with value types like structs.
{
/* The garbage collector will keep the instance referenced by `i` alive for us as long as necessary. So, there is no need to copy the instance unless we want to be able to mutate it elsewhere without affecting the instance refrenced by
    `map`. */

/* `typeid(i)` will compile, but probably doesn't do what you want: you need to retrieve the value using the same key you put it in with, and below that has
    to be `typeid(I)`: */
    map[typeid(I)] = cast(Object) i;
}

I get(I)()
if(is(I == interface)) // This wouldn't work right with value types like structs.
{
/* This will return `null` if the value isn't really a reference to an instance of a subtype of `I`, or if the key isn't in the map yet. If you don't care about the latter case, it can be shortened to just `cast(I) map[I.stringof]`. */
    auto valuePtr = (typeid(I) in map);
    return (valuePtr is null)? null : cast(I) *valuePtr;
}
////////////////////////////////////////////

Many variations on this are possible, depending on exactly what you're really trying to accomplish. This is my best guess as to what you're after, though, without seeing the context for the code you posted.

However, it appears to produce garbage values on get().

Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns.... }

e.g.

void register(I)(I i) {
  auto mem = new void[](I.sizeof);
  memcpy(mem.ptr, cast(void*) i, I.sizeof);

  // CheckedPtr includes a hash of fullyQualifiedName
  map[i.get_name()] = CheckedPtr!I(mem.ptr);
}

I get(I)() {
  // basically cast(I) p
  return map[I.get_name()].as!I();
}

Your code confuses two levels of indirection (because D makes this super confusing); that is why it doesn't do what you want. `cast(void*) i` is an untyped pointer to some class instance, while `I.sizeof` is the size of *the pointer itself*, NOT the instance it points to.

`I` is *not* the type of an interface instance, it is the type of a reference to an instance of the interface. (A reference is a pointer that sometimes automatically dereferences itself.) So, I.sizeof is always (void*).sizeof, the size of a pointer.

The types of class and interface instances cannot be named or referenced in D, but `__traits(classInstanceSize, C)` will get you the size of an instance of class `C`. Getting the size of an interface instance isn't really a sensible thing to do, since the whole point of interfaces is that you don't need to know about the implementing type to work with them. Regardless, copying or moving the memory of a class instances directly is generally a bad idea, for various reasons.

Reply via email to