Thread overview
Why `foo.x.saa.aa` and `foo.y.saa.aa` is the same? `shared_AA.saa` should still be instance variable, not class variable, right?
Jun 25
mw
Jun 25
mw
Jun 25
Kagamin
Jun 25
mw
Jun 26
mw
Jun 26
mw
June 25

Sorry about the silly code, but I just tried this:

$ cat shared_aa.d
import std;

synchronized class shared_AA_class {
 private:
  int[int] aa;
  alias aa this;

 public:
  void print() {
	  writeln(&aa, aa);
  }
}

struct shared_AA {
  shared_AA_class saa = new shared_AA_class();  // by this syntax `saa` is still instance variable?
  alias saa this;
}

class Foo {
	shared shared_AA x;
	shared shared_AA y;

	this() {
		x[1] = 1;  // only modified `x`, not `y`
	}
}

void main() {
	Foo foo = new Foo();
	foo.x.print();
	foo.y.print();
	writeln(&(foo.x.saa));
	writeln(&(foo.y.saa));
}
$ dmd ./shared_aa
$ ./shared_aa
63B699474020[1:1]
63B699474020[1:1]
76CDDB518010
76CDDB518018
$ ldc2 shared_aa.d
$ ./shared_aa
558A95DF90C0[1:1]
558A95DF90C0[1:1]
743BE2B00010
743BE2B00018

Why foo.x.saa.aa and foo.y.saa.aa is the same? (and of course print out the same contents).

shared_AA.saa should still be instance variable, not class variable, right?

Thanks.

June 25
On 25/06/2024 2:16 PM, mw wrote:
> struct shared_AA {
>    shared_AA_class saa = new shared_AA_class();  // by this syntax `saa` is still instance variable?
>    alias saa this;
> }

When you specify an initializer like this, that instance of ``shared_AA_class`` gets put into the .init of ``shared_AA``.

It is shared between instances, even if its a field.

```d
import std.stdio;

struct Foo {
    ubyte value = 2;
}

void main() {
    writeln(cast(ubyte[])__traits(initSymbol, Foo)); // [2]
}
```
June 25
On Tuesday, 25 June 2024 at 02:25:14 UTC, Richard (Rikki) Andrew Cattermole wrote:
> On 25/06/2024 2:16 PM, mw wrote:
>> struct shared_AA {
>>    shared_AA_class saa = new shared_AA_class();  // by this syntax `saa` is still instance variable?
>>    alias saa this;
>> }
>
> When you specify an initializer like this, that instance of ``shared_AA_class`` gets put into the .init of ``shared_AA``.
>

This is confusing -- well, let's try something similar in C++ and Java:

```
$ cat shared_aa.cpp
#include <stdio.h>

class shared_AA_class {
public:
  int aa;
  shared_AA_class() {
	  printf("new shared_AA_class\n");
  }

  void print() {
	  printf("%d\n", aa);
  }
};

struct shared_AA {
  shared_AA_class* saa = new shared_AA_class();  // by this syntax `saa` is still instance variable
};

class Foo {
public:
 shared_AA x;
 shared_AA y;

 Foo() {
    x.saa->aa = 1;  // only modified `x`, not `y`
 }

};

int main() {

	Foo foo;

	foo.x.saa->print();
	foo.y.saa->print();

	printf("%d\n", foo.x.saa->aa);
	printf("%d\n", foo.y.saa->aa);
}

$ g++ shared_aa.cpp
$ ./a.out
new shared_AA_class
new shared_AA_class
1
0
1
0
```

The `shared_AA_class` ctor is called twice, and `foo.x.saa` and `foo.y.saa` are different object.


```
$ cat Foo.java
class shared_AA_class {
 public
  int aa;
  shared_AA_class() {
	  System.out.println("new shared_AA_class");
  }

  void print() {
	  System.out.println(aa);
  }
}

class shared_AA {
  shared_AA_class saa = new shared_AA_class();  // by this syntax `saa` is still instance variable
}

class Foo {
	 shared_AA x;
	 shared_AA y;

	Foo() {
    x = new shared_AA();
    y = new shared_AA();
		x.saa.aa = 1;  // only modified `x`, not `y`
	}

public static void main(String[] args) {

	Foo foo = new Foo();

	foo.x.saa.print();
	foo.y.saa.print();

	System.out.println(foo.x.saa.aa);
	System.out.println(foo.y.saa.aa);
}

}

$ javac Foo.java
$ java Foo
new shared_AA_class
new shared_AA_class
1
0
1
0


```

The `shared_AA_class` ctor is called twice, and `foo.x.saa` and `foo.y.saa` are different object.


Why D choose to be different here? i.e. `shared_AA_class saa = new shared_AA_class()` only evaluate only once, and even force it must be evaluate-able at compile time?


June 25
It's a bug.
June 25
On 25/06/2024 3:38 PM, mw wrote:
> Why D choose to be different here? i.e. |shared_AA_class saa = new shared_AA_class()| only evaluate only once, and even force it must be evaluate-able at compile time?

That has nothing to do with it.

Every type in D has an initialized value, that everything starts off as, byte for byte.

When you have a field with an initializer it gets put into that initialized value.

The constructor does not perform the initializer.
June 25

On Tuesday, 25 June 2024 at 02:16:25 UTC, mw wrote:

>

Why foo.x.saa.aa and foo.y.saa.aa is the same? (and of course print out the same contents).

shared_AA.saa should still be instance variable, not class variable, right?

saa is an instance variable, but both foo.x.saa and foo.y.saa are initialized to the same instance of shared_AA_class. I think in the next edition of D we can forbid tail mutable initializers.

BTW there's also another issue that the initializer is not TLS - that could probably be fixed (also in an edition) to use TLS.

https://forum.dlang.org/post/sexmkjnbtxvsvodcacjq@forum.dlang.org

June 25

On Tuesday, 25 June 2024 at 21:13:44 UTC, Nick Treleaven wrote:

>

On Tuesday, 25 June 2024 at 02:16:25 UTC, mw wrote:

>

Why foo.x.saa.aa and foo.y.saa.aa is the same? (and of course print out the same contents).

shared_AA.saa should still be instance variable, not class variable, right?

saa is an instance variable, but both foo.x.saa and foo.y.saa are initialized to the same instance of shared_AA_class. I think in the next edition of D we can forbid tail mutable initializers.

I think the main problem here is that most people come to D from Java / C++ world (among the most popular languages). This tail initializer's syntax looks the same, but the semantics is so different and so surprisingly unexpected! (as I demo-ed in my previous reply).

At least, we need to have a document for Java / C++ programmers, which clearly highlights such important differences.

June 26

On Tuesday, 25 June 2024 at 21:13:44 UTC, Nick Treleaven wrote:

>

I think in the next edition of D we can forbid tail mutable initializers.

It is still (or maybe only) useful for fields of a singleton class.

June 26

On Wednesday, 26 June 2024 at 01:17:01 UTC, mw wrote:

>

On Tuesday, 25 June 2024 at 21:13:44 UTC, Nick Treleaven wrote:

>

I think in the next edition of D we can forbid tail mutable initializers.

It is still (or maybe only) useful for fields of a singleton class.

But a compiler warning message will be very useful.