www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Class member always has the same address

reply szymski <szymskipl gmail.com> writes:
Hello!
I'm having a big problem with class members. I'm kinda new to D, 
so this may be my fault, but look at the following code:

import std.stdio;

class B {
	int variable;
}

class A {
	B b = new B();	
}

void main()
{
	// Create 10 instances of A
	foreach(i; 0 .. 10) {
		auto a = new A();

		writeln(&a.b.variable, " = ", a.b.variable); // Print 
a.b.variable address and its value 		a.b.variable++;
	}
}
When ran, it prints something totally different from what I expect:
430088 = 0
430088 = 1
430088 = 2
430088 = 3
430088 = 4
430088 = 5
430088 = 6
430088 = 7
430088 = 8
430088 = 9
In my opinion &a.b.variable should give different addresses for each instance of A, because it's not static. What am I doing wrong? Thanks in advance.
Mar 19 2016
next sibling parent ag0aep6g <anonymous example.com> writes:
On 19.03.2016 21:24, szymski wrote:
 In my opinion &a.b.variable should give different addresses for each
 instance of A, because it's not static. What am I doing wrong? Thanks in
 advance.
The As are different, but they all reference the same B. Initialize b in a constructor instead.
Mar 19 2016
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Saturday, 19 March 2016 at 20:24:15 UTC, szymski wrote:

class A {
	B b = new B();	
}
This is *default* initialization, not per instance initialization. The compiler will create one instance of B and it will become the default initializer of b in *every* instance of A. You can verify that with this: class B {} class A { B b = new B; } void main() { auto as = [new A, new A, new A]; assert(as[0].b is as[1].b); assert(as[1].b is as[2].b); assert(as[0].b is as[2].b); } Here, all of the asserts will pass. But add a constructor to A that does this: this() { b = new B; } And now the first assert will fail. This is *per-instance* initialization.
Mar 19 2016
parent reply szymski <szymskipl gmail.com> writes:
On Sunday, 20 March 2016 at 02:21:51 UTC, Mike Parker wrote:
 On Saturday, 19 March 2016 at 20:24:15 UTC, szymski wrote:

class A {
	B b = new B();	
}
This is *default* initialization, not per instance initialization. The compiler will create one instance of B and it will become the default initializer of b in *every* instance of A. You can verify that with this: class B {} class A { B b = new B; } void main() { auto as = [new A, new A, new A]; assert(as[0].b is as[1].b); assert(as[1].b is as[2].b); assert(as[0].b is as[2].b); } Here, all of the asserts will pass. But add a constructor to A that does this: this() { b = new B; } And now the first assert will fail. This is *per-instance* initialization.
Ok, I understand now, thanks. I used C# a lot before and there default initialization worked like per instance initialization.
Mar 20 2016
parent Mike Parker <aldacron gmail.com> writes:
On Sunday, 20 March 2016 at 09:53:07 UTC, szymski wrote:

 Ok, I understand now, thanks. I used C# a lot before and there 
 default initialization worked like per instance initialization.
Yes, I assumed you were thinking of C# or Java classes with this. When coming to a new language, it's natural to use the idioms you're used to. That isn't always going to work the way you expect. If you're lucky, you'll see compiler errors. Otherwise, you'll find yourself scratching your head at odd behavior. When you encounter such situations in D, the answer is often in the documentation or somewhere here in the forum
Mar 20 2016