Andrei Alexandrescu wrote:
I think this has been discussed in this group already.

An object storing another object needs two allocations:

class A { ... }
class B {
   A a;
   this() {
      a = new A;
   }
}

auto b = new B; // two allocations

I'm thinking of using "scope" in this situation to imply in-situ storage:

class B {
   scope A a;
   this() {
      a = new A;
   }
}

Now the A member actually lies inside of B - no more indirection. That means the constructor needs special scrutiny, in particular a cannot be null because that wouldn't make much sense.

What do you think?

I think it should be done in userland, not built-in. Here's a proof-of-concept implementation:

----
import std.stdio;


string scopeInstance(string type, string name) {
        return `
private byte[__traits(classInstanceSize, `~type~`)] _scopeInstance__`~name~`;

        static this() {
                const int off = _scopeInstance__`~name~`.offsetof;
                const int len = __traits(classInstanceSize, `~type~`);
                typeof(this).classinfo.init[off .. off + len] = 
`~type~`.classinfo.init;
        }

        `~type~` `~name~`() {
                return cast(`~type~`)_scopeInstance__`~name~`.ptr;
        }

        void `~name~`(`~type~` f) {
_scopeInstance__`~name~`[] = (cast(byte*)f)[0.._scopeInstance__`~name~`.sizeof];
        }`;
}

class Foo {
        int x;
        float y;
        string zomg = "zomg";

        this(int x, float y) {
                writeln("making a Foo");
                this.x = x;
                this.y = y;
        }

        ~this() {
                writeln("death-tracting a Foo");
        }
}

class Bar {
        string x;

        this (string x) {
                writeln("making a Bar");
                this.x = x;
        }
}

class Baz {
        mixin(scopeInstance("Foo", "foo"));
        mixin(scopeInstance("Bar", "bar"));

        this() {
                writeln("making a Baz");
                foo.__ctor(1, 3.14f);
                bar.__ctor("ohai");
        }

        ~this() {
                writeln("death-tracting a Baz");
                foo.__dtor();
        }
}


void main() {
        scope b = new Baz;
        writeln(b.foo.x, " ", b.foo.y, " ", b.foo.zomg);
        writeln(b.bar.x);
        writeln("Foo size: ", __traits(classInstanceSize, Foo));
        writeln("Bar size: ", __traits(classInstanceSize, Bar));
        writeln("Baz size: ", __traits(classInstanceSize, Baz));
}
----

Result:
----
making a Baz
making a Foo
making a Bar
1 3.14 zomg
ohai
Foo size: 24
Bar size: 16
Baz size: 48
death-tracting a Baz
death-tracting a Foo
----

Now for a brief summary:
* I couldn't get hold of the initializer of a class at compile-time. I've tried using symbol.mangleof ~ "6__initZ", but DMD told me it could not be an initializer for a static array. This forced me to initialize the 'inline' / 'scope' class instances in a static ctor. I'm not sure if this is legal - can ClassInfo ever wind up to live in ROM? Perhaps __traits(classInitializer, _) could be added. * The long proposed __ident extension would allow turning the string mixin into a regular template mixin.
* __ctor should be standardized (or is it?)

I'm not very good at D2, so perhaps there are better ways to implement it by now. Here's a similar proposal in pseudo-D2-code: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=85684


--
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode

Reply via email to