I'd like to create an instance, inject a couple of fields and only then call the constructor on that instance.
Example:
class Foo {
int a = 50;
int b;
this() {
assert(a == 50 && b == 10);
}
}
...
Foo bar = ???;
bar.b = 10;
bar.this();
Generally, Foo
might have multiple overloaded constructors.
What's the nicest way to do this, without interfering with the garbage collector and other language mechanisms?
EDIT: Most responses I've gotten so far were along the lines of "why the hell would you want to do that?!"
I'm currently using such @Annotation-driven system for 2 things: automated configuration loading and automated dependency injection. Both have shown to be big productivity gains for me so far and they also work wonders for responsibility decoupling. (see also: Single responsibility principle)
Though perhaps uncommon in D, similar approaches are widely used in other languages such as Java.
I'd say you should change your constructor to accept those arguments.
But if you really want to, you can break up "bar = new Foo();" into three steps:
__traits(classInstanceSize
)typeid().init
- this holds values for like your a=50, the pointer to the virtual table, etc.)And, of course, returning the new reference.
import core.memory; // for GC.malloc
enum size = __traits(classInstanceSize, Foo); // get the size
auto memory = GC.malloc(size)[0 .. size]; // alloc mem and slice it for bounds checking
memory[] = typeid(Foo).init[]; // initialize the memory
Foo foo = cast(Foo) memory.ptr; // we can now cast it to the reference
foo.b = 10; // here's your special line
foo.__ctor(); // and now call the constructor. Can pass any arguments here, D will handle the overloads normally
assert(foo.a == 50); // ensure everything worked
assert(foo.b == 10);
assert(typeid(foo) == typeid(Foo));
// BTW don't use the variable memory anymore - only use the typed Foo instance
Breaking down the steps like this also lets you replace the allocation method, if you want. Phobos' std.conv.emplace
function performs steps 2 and 3 in a single function, to make that easier with custom allocation.
But since you want to insert code between steps 2 and 3, you gotta do it yourself.