www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - WTF! new in class is static?!?!

reply DigitalDesigns <DigitalDesigns gmail.com> writes:
class A;

class B
{
    A a = new A();
}

auto b1 = new B();
auto b2 = new B();

assert(b1.a == b2.a)!!


I'm glad I finally found this out! This is not typical behavior 
in most languages is it?

I'd expect it to be translated to something like

class B
{
    A a;
    this()
    {
        a = new A();
    }
}


This has caused bugs in my code because the fields are all 
pointing to the same data when I expected them to each have 
unique data ;/

This method is error prone and the behavior should be reversed, 
it should not break the majority of code. If one wants the 
current behavior then static new could be used or something else.
Jun 07 2018
next sibling parent reply Ethan <gooberman gmail.com> writes:
On Thursday, 7 June 2018 at 21:07:26 UTC, DigitalDesigns wrote:
 assert(b1.a == b2.a)!!
The spec isn't clear on this but it uses the same rules as struct field initialisation, ie it's defined once and copied to each instance on creation. https://dlang.org/spec/struct.html#default_struct_init
Jun 07 2018
parent ag0aep6g <anonymous example.com> writes:
On 06/07/2018 11:26 PM, Ethan wrote:
 The spec isn't clear on this but it uses the same rules as struct field 
 initialisation, ie it's defined once and copied to each instance on 
 creation.
 
 https://dlang.org/spec/struct.html#default_struct_init
It says there that "The default initializers may not contain references to mutable data." DMD enforces that for pointers to primitives, but not for arrays, class objects, or even pointers to structs: ---- struct S { int* p = new int(1); /* Error: cannot use non-constant CTFE pointer in an initializer */ int[] a = [1, 2, 3]; /* no error */ C c = new C; /* no error */ S2* s = new S2; /* no error */ } class C { int x = 4; } struct S2 { int x = 5; } ---- Seems inconsistent to me.
Jun 07 2018
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 07, 2018 21:07:26 DigitalDesigns via Digitalmars-d-learn 
wrote:
 class A;

 class B
 {
     A a = new A();
 }

 auto b1 = new B();
 auto b2 = new B();

 assert(b1.a == b2.a)!!


 I'm glad I finally found this out! This is not typical behavior
 in most languages is it?

 I'd expect it to be translated to something like

 class B
 {
     A a;
     this()
     {
         a = new A();
     }
 }


 This has caused bugs in my code because the fields are all
 pointing to the same data when I expected them to each have
 unique data ;/

 This method is error prone and the behavior should be reversed,
 it should not break the majority of code. If one wants the
 current behavior then static new could be used or something else.
Well, if that compiles now with a non-immutable class object, then that was a language improvement. In any case, yes, the class object would be shared across all instances of the class. _Every_ type in D has an init value that they get default-initialized to before the constructor is run (assuming that the type even has a constructor). In the case of both classes and structs, whatever the member variables are directly initialized with make up the init value. So, if you have something like struct S { int i = 42; } then every instance of S will start with the value of 42 for i, and if you have something like struct S { int i = 42; this(int j) { i = j; } } then S.i is 42 before the constructor is run and will then be whatever it gets assigned to in the constructor after the constructor has run. The situation with classes is exactly the same as structs except that you don't have direct access to the init value (since you only ever deal with class references, not the classes themselves). One key result of this is that the class object is fully initialized to its init value for its exact type before _any_ constructors are called, so you don't get that problem that C++ has where the object isn't fully its correct type until all of the constructors have been called (so calling virtual functions from a class constructor in D actually works, unlike C++). All of this is quite clean with value types, but in the case of member variables that are pointers, dynamic arrays, or reference types that would mean that if you had something like struct S { int* ptr = new int(42); } every instance of S would have the same exact value for S.ptr, which can be surprising and is why it's sometimes been suggested that it not be legal to directly initialize member variables with mutable, non-value types. However, historically, this really only mattered for dynamic arrays, because originally it wasn't legal to directly initialize any member variable that was a pointer or reference, because the compiler and runtime weren't sophisticated enough to handle it. Several years ago, it was made possible to directly initialize immutable class references, but that doesn't really cause any problems, since sharing an immutable object doesn't cause problems. However, if it's now possible for the init value of an object to contain a mutable class reference or pointer, then the problem does get worse, and arguably, it becomes more critical to just make it illegal in the case of member variables in order to avoid the surprises (and bugs) that come when folks misunderstand what it really means to directly initialize a member variable in D. In any case, the way that D works here is a direct result of how init values work, and it really doesn't make sense for it to work any other way. At most, it would make sense to simply make it illegal to directly initialize types where it would be a problem. - Jonathan M Davis
Jun 07 2018
parent reply aliak <something something.com> writes:
On Thursday, 7 June 2018 at 21:32:54 UTC, Jonathan M Davis wrote:

 struct S
 {
     int* ptr = new int(42);
 }
Is that supposed to compile? -> https://run.dlang.io/is/SjUEOu Error: cannot use non-constant CTFE pointer in an initializer &[42][0]
Jun 07 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 07, 2018 22:43:50 aliak via Digitalmars-d-learn wrote:
 On Thursday, 7 June 2018 at 21:32:54 UTC, Jonathan M Davis wrote:
 struct S
 {

     int* ptr = new int(42);

 }
Is that supposed to compile? -> https://run.dlang.io/is/SjUEOu Error: cannot use non-constant CTFE pointer in an initializer &[42][0]
Not necessarily. It's the pointer equivalent of what the OP did with a mutable class reference, and I was using it for demonstrative purposes. The mutable class reference case didn't used to compile (it used to have to be immutable). This example is just the logic of what happens if it's legal with pointers too. If it hasn't been changed to be legal with pointers like it has been with classes, then that's arguably a good thing. - Jonathan M Davis
Jun 08 2018
parent aliak00 <something something.com> writes:
On Friday, 8 June 2018 at 18:18:27 UTC, Jonathan M Davis wrote:
 On Thursday, June 07, 2018 22:43:50 aliak via 
 Digitalmars-d-learn wrote:
 On Thursday, 7 June 2018 at 21:32:54 UTC, Jonathan M Davis 
 wrote:
 [...]
Is that supposed to compile? -> https://run.dlang.io/is/SjUEOu Error: cannot use non-constant CTFE pointer in an initializer &[42][0]
Not necessarily. It's the pointer equivalent of what the OP did with a mutable class reference, and I was using it for demonstrative purposes. The mutable class reference case didn't used to compile (it used to have to be immutable). This example is just the logic of what happens if it's legal with pointers too. If it hasn't been changed to be legal with pointers like it has been with classes, then that's arguably a good thing. - Jonathan M Davis
Boh, it seems it actually has, just not with primitive types it seems: struct A { int i = 3; } struct B { auto a = new A(3); } Above compile fine :o
Jun 09 2018
prev sibling next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 7 June 2018 at 21:07:26 UTC, DigitalDesigns wrote:
 class A;

 class B
 {
    A a = new A();
 }

 auto b1 = new B();
 auto b2 = new B();

 assert(b1.a == b2.a)!!


 I'm glad I finally found this out! This is not typical behavior 
 in most languages is it?

 I'd expect it to be translated to something like

 class B
 {
    A a;
    this()
    {
        a = new A();
    }
 }


 C++. This has caused bugs in my code because the fields are all 
 pointing to the same data when I expected them to each have 
 unique data ;/

 This method is error prone and the behavior should be reversed, 
 it should not break the majority of code. If one wants the 
 current behavior then static new could be used or something 
 else.
If you want a new one use a constructor call. initalizers are support to be static, this only works because ctfe supports newing classes.
Jun 07 2018
prev sibling next sibling parent Cym13 <cpicard openmailbox.org> writes:
On Thursday, 7 June 2018 at 21:07:26 UTC, DigitalDesigns wrote:
 class A;

 class B
 {
    A a = new A();
 }

 auto b1 = new B();
 auto b2 = new B();

 assert(b1.a == b2.a)!!


 I'm glad I finally found this out! This is not typical behavior 
 in most languages is it?

 I'd expect it to be translated to something like

 class B
 {
    A a;
    this()
    {
        a = new A();
    }
 }


 C++. This has caused bugs in my code because the fields are all 
 pointing to the same data when I expected them to each have 
 unique data ;/

 This method is error prone and the behavior should be reversed, 
 it should not break the majority of code. If one wants the 
 current behavior then static new could be used or something 
 else.
The spec looks pretty clear to me on that point https://dlang.org/spec/class.html#field-init Besides, defining behaviour at construction is what constructors are for, I wouldn't expect anything outside a constructor to happen when an object is constructed. So while I understand that other languages may (successfully for them) do things differently I don't think I'd like a breaking change for that.
Jun 07 2018
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 7 June 2018 at 21:07:26 UTC, DigitalDesigns wrote:
 I'm glad I finally found this out! This is not typical behavior 
 in most languages is it?
I don't think most languages allow this, and D used to not allow it either, but then CTFE got class support and it got enabled. If you understand how it works, it is sometimes useful... But, it is confusing for a *lot* of people so it might make sense to ban it again - or at least make it more obvious that this is what you intended when you write it.
Jun 07 2018
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/7/18 5:07 PM, DigitalDesigns wrote:
 class A;
 
 class B
 {
     A a = new A();
 }
 
 auto b1 = new B();
 auto b2 = new B();
 
 assert(b1.a == b2.a)!!
Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old! -Steve
Jun 07 2018
next sibling parent reply DigitalDesigns <DigitalDesigns gmail.com> writes:
On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer 
wrote:
 On 6/7/18 5:07 PM, DigitalDesigns wrote:
 class A;
 
 class B
 {
     A a = new A();
 }
 
 auto b1 = new B();
 auto b2 = new B();
 
 assert(b1.a == b2.a)!!
Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old! -Steve
wait! everyone is saying it is a feature! So, which is it, a feature or a bug?!?!?
Jun 07 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/7/18 6:58 PM, DigitalDesigns wrote:
 On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer wrote:
 On 6/7/18 5:07 PM, DigitalDesigns wrote:
 class A;

 class B
 {
     A a = new A();
 }

 auto b1 = new B();
 auto b2 = new B();

 assert(b1.a == b2.a)!!
Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old!
wait! everyone is saying it is a feature! So, which is it, a feature or a bug?!?!?
It's a feature that you can assign a static initializer to a class or struct member and have that work at compile time (using CTFE). But when it's a reference to mutable data, it's a bug. Just the idea that you have implicitly shared data if you create instances in multiple threads should make it obviously a bug. Even back then it was a debate, look at the bug report. But it's definitely a bug. Just hard to close since it will probably break a lot of code. -Steve
Jun 07 2018
parent DigitalDesigns <DigitalDesigns gmail.com> writes:
On Thursday, 7 June 2018 at 23:08:22 UTC, Steven Schveighoffer 
wrote:
 On 6/7/18 6:58 PM, DigitalDesigns wrote:
 On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer 
 wrote:
 On 6/7/18 5:07 PM, DigitalDesigns wrote:
 class A;

 class B
 {
     A a = new A();
 }

 auto b1 = new B();
 auto b2 = new B();

 assert(b1.a == b2.a)!!
Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old!
wait! everyone is saying it is a feature! So, which is it, a feature or a bug?!?!?
It's a feature that you can assign a static initializer to a class or struct member and have that work at compile time (using CTFE). But when it's a reference to mutable data, it's a bug. Just the idea that you have implicitly shared data if you create instances in multiple threads should make it obviously a bug. Even back then it was a debate, look at the bug report. But it's definitely a bug. Just hard to close since it will probably break a lot of code. -Steve
I would expect that using a static initialize would not break as much code going from immutable to mutable than the other way around. Someone should have been smart enough to create a static new so both methods could have been implemented in a sane way.
Jun 07 2018
prev sibling parent reply KingJoffrey <KingJoffrey KingJoffrey.com> writes:
On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer 
wrote:
 Yep, long-standing issue: 
 https://issues.dlang.org/show_bug.cgi?id=2947

 Almost a decade old!

 -Steve
Another reason why I still refuse to bring my code to D. As if the module not respecting class encapsulation was not enough (see my rants about it elsewhere), D even allows two class instances to share non static mutable data!! wtf! -------------- import std.stdio; class A { int[] c = [3,3]; } void main() { A ca = new A; A cb = new A; ca.c[0] = 44; writeln(cb.c[0]); - print 3) } ---------------
Jun 09 2018
parent reply bauss <jj_1337 live.dk> writes:
On Saturday, 9 June 2018 at 09:24:48 UTC, KingJoffrey wrote:
 On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer 
 wrote:
 Yep, long-standing issue: 
 https://issues.dlang.org/show_bug.cgi?id=2947

 Almost a decade old!

 -Steve
Another reason why I still refuse to bring my code to D. As if the module not respecting class encapsulation was not enough (see my rants about it elsewhere), D even allows two class instances to share non static mutable data!! wtf! -------------- import std.stdio; class A { int[] c = [3,3]; } void main() { A ca = new A; A cb = new A; ca.c[0] = 44; writeln(cb.c[0]); correctly - print 3) } ---------------
Nobody cares about your opinion. Nobody is forcing you to write code like that. In fact most programs will be written without such code, for good reason. Regardless if it does the "correct" thing or not.
Jun 09 2018
parent reply RealProgrammer <deva deva.com> writes:
On Saturday, 9 June 2018 at 11:47:54 UTC, bauss wrote:
 Nobody cares about your opinion.

 Nobody is forcing you to write code like that.

 In fact most programs will be written without such code, for 
 good reason.

 Regardless if it does the "correct" thing or not.
Dude. That response is so childish. Don't speak to people like that. And given that no mainstream compiler would allow you to share mutable data like that, maybe you and others in the D 'community' should start paying attention to the 'opinions' of those who do professional development with professional compilers.
Jun 09 2018
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
But unlike you "king", Bauss isn't using tor to ban evade.
Jun 09 2018
parent reply KingJoffrey <KingJoffrey KingJoffrey.com> writes:
On Saturday, 9 June 2018 at 12:56:55 UTC, rikki cattermole wrote:
 But unlike you "king", Bauss isn't using tor to ban evade.
why you wanna ban little old me? is it cause I made a crticism of D? did i hurt your feelings? ..and everyone I know uses tor - and you should too - whether you're evading something or not - otherwise tor has no value - cause sites will just block tor - and then all those people that use tor for advancing human rights around the world, will lose the platform they need to do that, without being persecuted, cause they criticised something.
Jun 09 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Saturday, 9 June 2018 at 13:24:49 UTC, KingJoffrey wrote:
 On Saturday, 9 June 2018 at 12:56:55 UTC, rikki cattermole 
 wrote:
 But unlike you "king", Bauss isn't using tor to ban evade.
why you wanna ban little old me? is it cause I made a crticism of D?
No, because you been caught making imposter accounts left and right. Which btw we can tell as your poor attempts to imposter me.
Jun 09 2018
parent 12345swordy <12345swordy 12345swordy.com> writes:
On Saturday, 9 June 2018 at 13:49:48 UTC, 12345swordy wrote:
 No, because you been caught making imposter accounts left and 
 right. Which btw we can tell as your poor attempts to imposter 
 me.
Well... why ya all r busy havin a go at me, the bugs remains (as do all D'other bugs).
Jun 09 2018
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Saturday, 9 June 2018 at 12:40:07 UTC, RealProgrammer wrote:
 maybe you and others in the D 'community' should start paying 
 attention to the 'opinions' of those who do professional 
 development with professional compilers.
I do professional work with a professional compiler aka. The D compiler and I've been doing so for years.
Jun 09 2018
parent reply KingJoffrey <KingJoffrey KingJoffrey.com> writes:
On Sunday, 10 June 2018 at 01:27:50 UTC, bauss wrote:
 On Saturday, 9 June 2018 at 12:40:07 UTC, RealProgrammer wrote:
 maybe you and others in the D 'community' should start paying 
 attention to the 'opinions' of those who do professional 
 development with professional compilers.
I do professional work with a professional compiler aka. The D compiler and I've been doing so for years.
Well then, you should like my idea for the dconf '2019' logo... Dman and a bug, holding hands, and the bug saying "I'm not a bug, I'm a feature!".
Jun 09 2018
parent Bauss <jj_1337 live.dk> writes:
On Sunday, 10 June 2018 at 02:34:11 UTC, KingJoffrey wrote:
 On Sunday, 10 June 2018 at 01:27:50 UTC, bauss wrote:
 On Saturday, 9 June 2018 at 12:40:07 UTC, RealProgrammer wrote:
 maybe you and others in the D 'community' should start paying 
 attention to the 'opinions' of those who do professional 
 development with professional compilers.
I do professional work with a professional compiler aka. The D compiler and I've been doing so for years.
Well then, you should like my idea for the dconf '2019' logo... Dman and a bug, holding hands, and the bug saying "I'm not a bug, I'm a feature!".
Sure, because other compilers do not have bugs.
Jun 10 2018