scope class members -> in-situ

Tom S h3r3tic at remove.mat.uni.torun.pl
Fri Oct 2 10:33:18 PDT 2009


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



More information about the Digitalmars-d mailing list