digitalmars.D.learn - Struct constructor, opCall mess.
- Remo (21/21) Feb 24 2014 Hi,
- Tobias Pankrath (7/12) Feb 24 2014 The design of D relies on the fact that every type has a T.init
- Remo (8/22) Feb 24 2014 Well fortunately it seems to be possible to override init
- Stanislav Blinov (42/48) Feb 24 2014 Fortunately? I think not. It's an abomination that, IMO, has to
- Remo (29/81) Feb 24 2014 Yes I think it is. Of course it could be made a more safe in some
- Remo (4/10) Feb 24 2014 IMHO Issue 7066 is not a bug but a feature.
- Jesse Phillips (8/10) Feb 24 2014 I believe it is ready for production, but you can't expect it to
- Tobias Pankrath (4/7) Feb 24 2014 If someone thinks that C++ was production ready in 1998, just go
- Maxim Fomin (65/82) Feb 24 2014 1) Please comment after previous speaker, not before.
- monarch_dodra (24/26) Feb 24 2014 Honestly, you can't, and you shouldn't try either. There "used"
- Remo (7/34) Feb 24 2014 Thanks, I will try to make this this way and look how well it
- Jesse Phillips (3/6) Feb 24 2014 Here is the place I know of:
- Maxim Fomin (54/68) Feb 24 2014 The design of D relies on Andrei opinion. He is indeed convinced
- Remo (16/88) Feb 25 2014 Thanks for all this replies.
Hi, right now I am truing to figure out how the constructors behave in D2. Question 1: why it is not possible to create custom ctor for struct? I know this is not really necessary because you can initialize fields like this. struct S{ int i = 1; } But this is a big problem if one tries to port C++ code to D2 and default ctor call some important initialization code. Question 2: is there a way to mimic compiler generated ctor (that work in CTFE)? Question 3: why it is possible to call static opCall like this? VectorC v5 = v4(1.0); Right now opCall seems to be better as this(...) because it work in CTFE but because of unwanted calls this is not well at all. Question 4: why this(...) does not work in CTFE mode? Here is highly simplified test code. http://melpon.org/wandbox/permlink/ofvNby99mKqOBQBf I am asking this because I am learning D2 now by porting and warping/connecting some big C++ (C++11) project to D2.
Feb 24 2014
On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:Hi, right now I am truing to figure out how the constructors behave in D2. Question 1: why it is not possible to create custom ctor for struct?The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example. You need to pick one T.init or default constructors and D picked T.init.
Feb 24 2014
On Monday, 24 February 2014 at 14:14:43 UTC, Tobias Pankrath wrote:On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:Well fortunately it seems to be possible to override init property. But it still does not called at struct construction. http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJa So what is proper/best way to mimic default constructor for struct ?Hi, right now I am truing to figure out how the constructors behave in D2. Question 1: why it is not possible to create custom ctor for struct?The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example. You need to pick one T.init or default constructors and D picked T.init.
Feb 24 2014
On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:Well fortunately it seems to be possible to override init property.Fortunately? I think not. It's an abomination that, IMO, has to be annihilated. Recently Andrei suggested adding more explicit semantics to .init that may give some leeway in this matter, although this was concerning classes and non-null default values, so it may not concern structs at all. Regardless, my advice - don't try to override .init, i.e. don't invite trouble into your code :)But it still does not called at struct construction. http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJaYup.So what is proper/best way to mimic default constructor for struct ?Don't do it. Default construction for struct *is* initialization of its fields. If you want to do something other that initialize fields - create a function and call it explicitly. D is not C++, don't expect it to behave identically. To make it easier when porting code, you can always temporarily disable this() so the compiler will stop whenever you'd use your "special" default construction in C++. As you've mentioned, the code from your example doesn't need any special default constructors at all, this will work just fine: struct Vector(T) { T x = 0, y = 0, z = 0; this(T v) { x = y = z = v; } this(T x, T y, T z) { this.x = x; this.y = y; this.z = z; } } unittest { Vector!double v; auto v2 = Vector!double(1); auto v3 = Vector!double(1,2,3); assert(v.x == v.y && v.y == v.z && v.z == 0); assert(v2.x == v2.x && v2.y == v2.z && v2.z == 1); assert(v3.x == 1 && v3.y == 2 && v3.z == 3); } Also please take a look at those: https://d.puremagic.com/issues/show_bug.cgi?id=3438 https://d.puremagic.com/issues/show_bug.cgi?id=6080 https://d.puremagic.com/issues/show_bug.cgi?id=7066 https://d.puremagic.com/issues/show_bug.cgi?id=7597 https://d.puremagic.com/issues/show_bug.cgi?id=8816 https://d.puremagic.com/issues/show_bug.cgi?id=8817 https://d.puremagic.com/issues/show_bug.cgi?id=10413 https://d.puremagic.com/issues/show_bug.cgi?id=11307 There may be some others I've missed; the sheer amount and unresolved state is terrifying.
Feb 24 2014
Fortunately?Yes I think it is. Of course it could be made a more safe in some way. I think the big advantage of D is that it has 'bridge' to C and C++. This way it appears to be easy to port some C++ code to D. And it appears to be easy to interconnect C++ and D code. (via Dll for example)disable this()Yes this is possible. But then why it is not possible to use something like this ? default this(); For Vector example this works pretty well this way. But my main problem is more complicated. extern(C) int init(ref CWrapper p); extern(C) void free(ref CWrapper p); struct CWrapper { //some data that must be the same at C side. Data m_data; this() { init(&this); } ~this() { free(&this); } } How to do something like this in D ? Using class appears for me to be wrong direction. On Monday, 24 February 2014 at 18:13:02 UTC, Stanislav Blinov wrote:On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:Well fortunately it seems to be possible to override init property.Fortunately? I think not. It's an abomination that, IMO, has to be annihilated. Recently Andrei suggested adding more explicit semantics to .init that may give some leeway in this matter, although this was concerning classes and non-null default values, so it may not concern structs at all. Regardless, my advice - don't try to override .init, i.e. don't invite trouble into your code :)But it still does not called at struct construction. http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJaYup.So what is proper/best way to mimic default constructor for struct ?Don't do it. Default construction for struct *is* initialization of its fields. If you want to do something other that initialize fields - create a function and call it explicitly. D is not C++, don't expect it to behave identically. To make it easier when porting code, you can always temporarily disable this() so the compiler will stop whenever you'd use your "special" default construction in C++. As you've mentioned, the code from your example doesn't need any special default constructors at all, this will work just fine: struct Vector(T) { T x = 0, y = 0, z = 0; this(T v) { x = y = z = v; } this(T x, T y, T z) { this.x = x; this.y = y; this.z = z; } } unittest { Vector!double v; auto v2 = Vector!double(1); auto v3 = Vector!double(1,2,3); assert(v.x == v.y && v.y == v.z && v.z == 0); assert(v2.x == v2.x && v2.y == v2.z && v2.z == 1); assert(v3.x == 1 && v3.y == 2 && v3.z == 3); } Also please take a look at those: https://d.puremagic.com/issues/show_bug.cgi?id=3438 https://d.puremagic.com/issues/show_bug.cgi?id=6080 https://d.puremagic.com/issues/show_bug.cgi?id=7066 https://d.puremagic.com/issues/show_bug.cgi?id=7597 https://d.puremagic.com/issues/show_bug.cgi?id=8816 https://d.puremagic.com/issues/show_bug.cgi?id=8817 https://d.puremagic.com/issues/show_bug.cgi?id=10413 https://d.puremagic.com/issues/show_bug.cgi?id=11307 There may be some others I've missed; the sheer amount and unresolved state is terrifying.
Feb 24 2014
IMHO Issue 7066 is not a bug but a feature. Of course it could be handled i a bit more safe way. This looks like D2 is still in Beta stadium and not really ready for production use !?Also please take a look at those: https://d.puremagic.com/issues/show_bug.cgi?id=7066 There may be some others I've missed; the sheer amount and unresolved state is terrifying.
Feb 24 2014
On Monday, 24 February 2014 at 20:35:54 UTC, Remo wrote:This looks like D2 is still in Beta stadium and not really ready for production use !?I believe it is ready for production, but you can't expect it to be ready in all cases. Mostly its lack of readiness isn't because of the language though. For example it isn't ready for production Android/iOS development, because it hasn't been done yet. It isn't ready for Epic to write Unreal 5 Engine in it. However if Valve believed in D I'd say it was ready for them to take on the challenge and write Source 2 in D.
Feb 24 2014
On Tuesday, 25 February 2014 at 06:06:22 UTC, Jesse Phillips wrote:On Monday, 24 February 2014 at 20:35:54 UTC, Remo wrote:If someone thinks that C++ was production ready in 1998, just go and try a C++ compiler from this time.This looks like D2 is still in Beta stadium and not really ready for production use !?
Feb 24 2014
On Monday, 24 February 2014 at 19:41:57 UTC, Remo wrote:For Vector example this works pretty well this way. But my main problem is more complicated. extern(C) int init(ref CWrapper p); extern(C) void free(ref CWrapper p); struct CWrapper { //some data that must be the same at C side. Data m_data; this() { init(&this); } ~this() { free(&this); } } How to do something like this in D ? Using class appears for me to be wrong direction.1) Please comment after previous speaker, not before. You can't avoid default struct constructor problem if functions which you call in constructors are not at least CTFEable because you would need to call them if you wish to define default struct constructor. Since this is not your case, you can do: 2) You can use static OpCall, Voldemort type or alias this. In case of alias this it looks like: extern(C) int printf(const char*, ...); extern(C) int init(CWrapper* p) { printf("init\n"); return 0; } extern(C) void d_free(CWrapper* p) { printf("free\n"); } struct Data { void do_something(){} } struct CWrapper { //some data that must be the same at C side. Data m_data; bool m_init; /*this(int) { init(&this); }*/ ~this() { d_free(&this); } Data get() { if (!m_init) init(&this); return m_data; } alias get this; } void main() { CWrapper cw; cw.do_something(); } In case of Voldermort struct some struct is defined inside function, so the only way (in theory) to create an instance is to call that function. It is inconviniet but guarantees that you will not have non initialzed structs (in theory). extern(C) int printf(const char*,...); auto make_struct() { struct Data{} struct CWrapper { extern(C) int m_init(CWrapper* p){ return 0; } extern(C) void m_free(CWrapper* p){ printf("free\n");} //some data that must be the same at C side. Data m_data; this(int) { m_init(&this); } ~this() { m_free(&this); } } return CWrapper(0); } void main() { auto x = make_struct(); } 4) Please do not define free() function.
Feb 24 2014
On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:So what is proper/best way to mimic default constructor for struct ?Honestly, you can't, and you shouldn't try either. There "used" to be the static opCall that allowed: ---- auto a = T(); ---- But: a) This is being phased out: If T has a constructor, it will seize to compile. b) It's not "default": "T a;" will still compile, but not construct. The feedback I've been getting is that the "correct" way to guarantee construction is to do it via a named factory pattern. You disable the this(), so as to "force" initialization, and make the constructors private. You'll get something along the lines of: T a; //Nope. T a = T(); //Nope T a = T.build(); //OK! T a = T(1, 2); //Nope! T a = T.build(1, 2); //OK! T a = T.init; //OK! Special explicit requrest for non-initialisation. With D's move semantics and (N)RVO, there should be 0 overhead to do this.
Feb 24 2014
On Monday, 24 February 2014 at 21:06:03 UTC, monarch_dodra wrote:On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:Thanks, I will try to make this this way and look how well it will work. But it could complicate connection from C++ to D and back. Where I can find more info about 'D's move semantics'? Apparently it is not the same as rvalue reference and move semantics in C++11 ?So what is proper/best way to mimic default constructor for struct ?Honestly, you can't, and you shouldn't try either. There "used" to be the static opCall that allowed: ---- auto a = T(); ---- But: a) This is being phased out: If T has a constructor, it will seize to compile. b) It's not "default": "T a;" will still compile, but not construct. The feedback I've been getting is that the "correct" way to guarantee construction is to do it via a named factory pattern. You disable the this(), so as to "force" initialization, and make the constructors private. You'll get something along the lines of: T a; //Nope. T a = T(); //Nope T a = T.build(); //OK! T a = T(1, 2); //Nope! T a = T.build(1, 2); //OK! T a = T.init; //OK! Special explicit requrest for non-initialisation. With D's move semantics and (N)RVO, there should be 0 overhead to do this.
Feb 24 2014
On Monday, 24 February 2014 at 23:34:51 UTC, Remo wrote:Where I can find more info about 'D's move semantics'? Apparently it is not the same as rvalue reference and move semantics in C++11 ?Here is the place I know of: http://dconf.org/2013/talks/cehreli.html
Feb 24 2014
On Monday, 24 February 2014 at 14:14:43 UTC, Tobias Pankrath wrote:On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:The design of D relies on Andrei opinion. He is indeed convinced that default constructors are impossible. However, you can write "default constructor" right now like: struct S { Type t; this(int) { t = whather_is_callable_in_CTFE(); } } enum E : S { A = S(0) } void main() { E e; assert (e.t == whather_is_callable_in_CTFE()); } Since compiler does this, it can also accept straight syntax and semantic: struct S { Type t; this() // proxibited default constructor now { t = whather_is_callable_in_CTFE(); } } What D really lacks is ability to call function in runtime after struct instance creation like: struct S { runtime this() {} ~this(){} } lowering to: S s; s.__runtime_ctor(); However, since compiler does this all over the place (postblits, copy constructors, destructors, etc.) There is no conceptual difference between having: S s s.__runtime_ctor(); and S s; s.__dtor(); In other words, there is no objective necessity not to have compile time and runtime default struct constructors since compiler already heavily does conceptually and technically similar things.Hi, right now I am truing to figure out how the constructors behave in D2. Question 1: why it is not possible to create custom ctor for struct?The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example. You need to pick one T.init or default constructors and D picked T.init.
Feb 24 2014
On Tuesday, 25 February 2014 at 07:59:33 UTC, Maxim Fomin wrote:On Monday, 24 February 2014 at 14:14:43 UTC, Tobias Pankrath wrote:Thanks for all this replies. Now I have better idea how it supposed to work. Yes something like runtime this() {} would be really great! https://d.puremagic.com/issues/show_bug.cgi?id=3438On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:The design of D relies on Andrei opinion. He is indeed convinced that default constructors are impossible. However, you can write "default constructor" right now like: struct S { Type t; this(int) { t = whather_is_callable_in_CTFE(); } } enum E : S { A = S(0) } void main() { E e; assert (e.t == whather_is_callable_in_CTFE()); } Since compiler does this, it can also accept straight syntax and semantic: struct S { Type t; this() // proxibited default constructor now { t = whather_is_callable_in_CTFE(); } } What D really lacks is ability to call function in runtime after struct instance creation like: struct S { runtime this() {} ~this(){} } lowering to: S s; s.__runtime_ctor(); However, since compiler does this all over the place (postblits, copy constructors, destructors, etc.) There is no conceptual difference between having: S s s.__runtime_ctor(); and S s; s.__dtor(); In other words, there is no objective necessity not to have compile time and runtime default struct constructors since compiler already heavily does conceptually and technically similar things.Hi, right now I am truing to figure out how the constructors behave in D2. Question 1: why it is not possible to create custom ctor for struct?The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example. You need to pick one T.init or default constructors and D picked T.init.I think at some point we'll need to support default constructors that executecode. This was posted 2009-10-23 and now years later it is still not possible. :( Unfortunately this problems and workarounds makes porting C++ to D2 more complicated. Here are is also a small experiment that also show that 'ref' is also necessary in D2 just like in C++. There seems to be no optimization for this so using 'in' or nothing at all is slower and may have side effects. http://melpon.org/wandbox/permlink/FyaksIPW4u1dNpwh
Feb 25 2014