On Friday, 1 January 2021 at 13:34:16 UTC, Adam wrote:
A a = new A; // I would expect this to be called for each "new B".
Your expectation is wrong for D. Since that's in a `static` context, it is run at compile time.
Any variable marked `static`, `__gshared`, or is struct/class/module-top-level member is a static context. So all those are set up at compile time (or triggers a compile error if this fails btw, either a thing is a static context and thus CTFEd or not a static context and thus never CTFEd) and just blindly copied at run time.
Basically any assignment outside a function is a compile time thing.
Is this intended?
Yes, it is a frequent thing to surprise people though. The reference there is part of the object but it points to the same default thing because of how that was made.
Constructors are actually run at runtime, but initializers are considered compile time constants.
My gut reaction is the compiler is memoising "new A" because purity is inferred
note that ctfe never happens because of anything inferred or pure or stuff like that. It is purely decided by the initialization context.
I can fix using a dedicated constructor, but I much prefer initializers where possible.
no real choice here, if you want a unique object to be referenced it needs to run with the constructor.