www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why `foo.x.saa.aa` and `foo.y.saa.aa` is the same? `shared_AA.saa`

reply mw <mingwu gmail.com> writes:
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.
Jun 24
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
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] } ```
Jun 24
parent reply mw <mingwu gmail.com> writes:
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?
Jun 24
next sibling parent Kagamin <spam here.lot> writes:
It's a bug.
Jun 24
prev sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
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.
Jun 25
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
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
Jun 25
next sibling parent mw <mingwu gmail.com> writes:
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.
Jun 25
prev sibling parent reply mw <mw g.c> writes:
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.
Jun 25
parent mw <mw g.c> writes:
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.
Jun 25