digitalmars.D.learn - Why `foo.x.saa.aa` and `foo.y.saa.aa` is the same? `shared_AA.saa`
- mw (54/54) Jun 24 Sorry about the silly code, but I just tried this:
- Richard (Rikki) Andrew Cattermole (13/18) Jun 24 When you specify an initializer like this, that instance of
- mw (93/101) Jun 24 This is confusing -- well, let's try something similar in C++ and
- Kagamin (1/1) Jun 24 It's a bug.
- Richard (Rikki) Andrew Cattermole (7/10) Jun 25 That has nothing to do with it.
- Nick Treleaven (8/12) Jun 25 `saa` is an instance variable, but both `foo.x.saa` and
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
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
On Tuesday, 25 June 2024 at 02:25:14 UTC, Richard (Rikki) Andrew Cattermole wrote:On 25/06/2024 2:16 PM, mw wrote: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?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``.
Jun 24
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
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
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: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.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.
Jun 25
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
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:But a compiler warning message will be very useful.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