Thread overview
Class member always has the same address
Mar 19, 2016
szymski
Mar 19, 2016
ag0aep6g
Mar 20, 2016
Mike Parker
Mar 20, 2016
szymski
Mar 20, 2016
Mike Parker
March 19, 2016
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.

March 19, 2016
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.
March 20, 2016
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.


March 20, 2016
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.
March 20, 2016
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