digitalmars.D - Would love to override default ctor of struct
- Dru (6/6) Jan 19 2019 What is the idea behind why we can't define default ctor for
- Alex (3/9) Jan 19 2019 If your constructor doesn't need any arguments, what is the
- Basile B. (6/17) Jan 19 2019 I see your point but...
- Alex (8/26) Jan 19 2019 Ok. And why this is a problem? I mean, if the sharedness is not
- Nick Treleaven (13/19) Jan 21 2019 Performance for repeated function calls after construction, we
- Alex (4/25) Jan 21 2019 Could you give an example, where a zero argument construction has
- Meta (35/38) Jan 21 2019 For the following reason, although the default argument
- Alex (3/10) Jan 21 2019 Ok, and I'm wondering what of this initialization cannot be done
- aliak (40/78) Jan 21 2019 Ok, so this confused me a bit, I seem to remember that when you
- Meta (5/94) Jan 21 2019 You're printing the address of the object reference, not the
- aliak (2/6) Jan 22 2019 Doh! Thanks.
- Neia Neutuladh (2/8) Jan 21 2019 E8 != F8.
- aliak (2/11) Jan 22 2019 lol. True.
- Jonathan M Davis (40/71) Jan 21 2019 A classic case would be some uses of RAII such as what MFC does with its
- Alex (4/51) Jan 21 2019 Ah!!
- Jonathan M Davis (46/52) Jan 19 2019 Structs in D don't actually have default constructors. Rather, they have...
- aliak (5/24) Jan 21 2019 I've always wondered why T.init can't be it's own thing and
- Jonathan M Davis (29/55) Jan 21 2019 If D allowed struct's to have a constructor without any parameters, it w...
- Dru (7/11) Jan 22 2019 the problem is construction of static variables right?
- Jonathan M Davis (10/21) Jan 23 2019 It's far from just static variables. For instance, init is a core part o...
- Nick Treleaven (12/18) Jan 31 2019 D could solve this by only allowing a nullary constructor when
- Jonathan M Davis (28/46) Jan 31 2019 The main problem with allowing a constructor with no parameters when you
- Nick Treleaven (20/38) Feb 07 2019 I'm not asking for a default constructor, only an explicit
- aliak (15/54) Feb 07 2019 It seems to me that the only argument I've heard to not allow
- Jonathan M Davis (69/107) Feb 08 2019 At the moment, the only situations that I can think of where casting to
- Guillaume Piolat (3/9) Jan 23 2019 Short answer: make T.init a value, and have your destructor be
- Guillaume Piolat (3/4) Jan 23 2019 Erratum: a _valid_ value
What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntax
Jan 19 2019
On Saturday, 19 January 2019 at 10:05:22 UTC, Dru wrote:What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxIf your constructor doesn't need any arguments, what is the reason you can't define default values to your members?
Jan 19 2019
On Saturday, 19 January 2019 at 10:18:34 UTC, Alex wrote:On Saturday, 19 January 2019 at 10:05:22 UTC, Dru wrote:I see your point but... 1. default member values (via initializer) are more like a shared this(). 2. not everything can be set using member initializer because of CTFE limitations.What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxIf your constructor doesn't need any arguments, what is the reason you can't define default values to your members?
Jan 19 2019
On Saturday, 19 January 2019 at 10:22:11 UTC, Basile B. wrote:On Saturday, 19 January 2019 at 10:18:34 UTC, Alex wrote:Ok. And why this is a problem? I mean, if the sharedness is not wanted, then, the thread id should go as a constructor parameter, shouldn't it?On Saturday, 19 January 2019 at 10:05:22 UTC, Dru wrote:I see your point but... 1. default member values (via initializer) are more like a shared this().What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxIf your constructor doesn't need any arguments, what is the reason you can't define default values to your members?2. not everything can be set using member initializer because of CTFE limitations.Hm... ok. But even then, if something does not work in the way it should because of limitations: What prevents of setting the parameter inside a function after or on creation? Or, using a non-default constructor exactly for these params?
Jan 19 2019
On Saturday, 19 January 2019 at 11:01:14 UTC, Alex wrote:Performance for repeated function calls after construction, we don't want an extra branch test on each function call and an extra bool bloating/tainting fields in the struct. A pseudo constructor function is a workaround, but is a bit ugly, adding a separate symbol you have to check for when learning a new library struct, and the function has more unnecessary boilerplate vs a constructor.2. not everything can be set using member initializer because of CTFE limitations.Hm... ok. But even then, if something does not work in the way it should because of limitations: What prevents of setting the parameter inside a function after or on creation?Or, using a non-default constructor exactly for these params?You can't have a zero argument non-default struct constructor. I've never been told why: https://wiki.dlang.org/Language_issues#Explicit_syntax_and_.40disable_this Only the default constructor is constrained by .init, explicit zero argument construction is unconstrained. It could be allowed.
Jan 21 2019
On Monday, 21 January 2019 at 17:06:55 UTC, Nick Treleaven wrote:On Saturday, 19 January 2019 at 11:01:14 UTC, Alex wrote:Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?Performance for repeated function calls after construction, we don't want an extra branch test on each function call and an extra bool bloating/tainting fields in the struct. A pseudo constructor function is a workaround, but is a bit ugly, adding a separate symbol you have to check for when learning a new library struct, and the function has more unnecessary boilerplate vs a constructor.2. not everything can be set using member initializer because of CTFE limitations.Hm... ok. But even then, if something does not work in the way it should because of limitations: What prevents of setting the parameter inside a function after or on creation?Or, using a non-default constructor exactly for these params?You can't have a zero argument non-default struct constructor. I've never been told why: https://wiki.dlang.org/Language_issues#Explicit_syntax_and_.40disable_this Only the default constructor is constrained by .init, explicit zero argument construction is unconstrained. It could be allowed.
Jan 21 2019
On Monday, 21 January 2019 at 19:08:49 UTC, Alex wrote:Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?For the following reason, although the default argument constructor hack no longer works: import std.stdio; struct Test(bool useFieldDefaultVal) { static if (useFieldDefaultVal) { int[] arr = [1, 2, 3]; } else { int[] arr; this(int dummy = 0) { arr = [1, 2, 3]; } } void doTest() { writeln("Address of arr: ", arr.ptr); } } void main() { Test!true t1; Test!true t2; // Deprecation: constructor `onlineapp.Test!false.Test.this` // all parameters have default arguments, but structs cannot // have default constructors. auto t3 = Test!false(); t1.doTest(); // Prints "Address of arr: 5622DAA0F010" t2.doTest(); // Prints "Address of arr: 5622DAA0F010" t3.doTest(); // Prints "Address of arr: null" }
Jan 21 2019
On Monday, 21 January 2019 at 20:50:45 UTC, Meta wrote:On Monday, 21 January 2019 at 19:08:49 UTC, Alex wrote:Ok, and I'm wondering what of this initialization cannot be done without a constructor?Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?For the following reason, although the default argument constructor hack no longer works: [...]
Jan 21 2019
On Monday, 21 January 2019 at 20:50:45 UTC, Meta wrote:On Monday, 21 January 2019 at 19:08:49 UTC, Alex wrote:Ok, so this confused me a bit, I seem to remember that when you static inisialize a class in the declaration scope of a struct, the same thing would happen as with arrays, i.e. they'd have the same address. But this turned out different: import std.stdio; class C {} struct Test(bool useFieldDefaultVal) { static if (useFieldDefaultVal) { C c = new C; } else { C c; this(int dummy = 0) { c = new C; } } void doTest() { writeln("Address of c: ", &c); } } void main() { Test!true t1; Test!true t2; // Deprecation: constructor `onlineapp.Test!false.Test.this` // all parameters have default arguments, but structs cannot // have default constructors. auto t3 = Test!false(); t1.doTest(); // Prints "Address of arr: 7FFE1322A7E8" t2.doTest(); // Prints "Address of arr: 7FFE1322A7F0" t3.doTest(); // Prints "Address of arr: 7FFE1322A7F8" } t1 and t2 have different addresses and t3 has t1's address?? Huh? Vat Khappened Khere?Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?For the following reason, although the default argument constructor hack no longer works: import std.stdio; struct Test(bool useFieldDefaultVal) { static if (useFieldDefaultVal) { int[] arr = [1, 2, 3]; } else { int[] arr; this(int dummy = 0) { arr = [1, 2, 3]; } } void doTest() { writeln("Address of arr: ", arr.ptr); } } void main() { Test!true t1; Test!true t2; // Deprecation: constructor `onlineapp.Test!false.Test.this` // all parameters have default arguments, but structs cannot // have default constructors. auto t3 = Test!false(); t1.doTest(); // Prints "Address of arr: 5622DAA0F010" t2.doTest(); // Prints "Address of arr: 5622DAA0F010" t3.doTest(); // Prints "Address of arr: null" }
Jan 21 2019
On Tuesday, 22 January 2019 at 01:18:24 UTC, aliak wrote:On Monday, 21 January 2019 at 20:50:45 UTC, Meta wrote:You're printing the address of the object reference, not the object itself (similar to printing the address of a pointer instead of the actual address it points to). Do `cast(void*)c` instead.On Monday, 21 January 2019 at 19:08:49 UTC, Alex wrote:Ok, so this confused me a bit, I seem to remember that when you static inisialize a class in the declaration scope of a struct, the same thing would happen as with arrays, i.e. they'd have the same address. But this turned out different: import std.stdio; class C {} struct Test(bool useFieldDefaultVal) { static if (useFieldDefaultVal) { C c = new C; } else { C c; this(int dummy = 0) { c = new C; } } void doTest() { writeln("Address of c: ", &c); } } void main() { Test!true t1; Test!true t2; // Deprecation: constructor `onlineapp.Test!false.Test.this` // all parameters have default arguments, but structs cannot // have default constructors. auto t3 = Test!false(); t1.doTest(); // Prints "Address of arr: 7FFE1322A7E8" t2.doTest(); // Prints "Address of arr: 7FFE1322A7F0" t3.doTest(); // Prints "Address of arr: 7FFE1322A7F8" } t1 and t2 have different addresses and t3 has t1's address?? Huh? Vat Khappened Khere?Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?For the following reason, although the default argument constructor hack no longer works: import std.stdio; struct Test(bool useFieldDefaultVal) { static if (useFieldDefaultVal) { int[] arr = [1, 2, 3]; } else { int[] arr; this(int dummy = 0) { arr = [1, 2, 3]; } } void doTest() { writeln("Address of arr: ", arr.ptr); } } void main() { Test!true t1; Test!true t2; // Deprecation: constructor `onlineapp.Test!false.Test.this` // all parameters have default arguments, but structs cannot // have default constructors. auto t3 = Test!false(); t1.doTest(); // Prints "Address of arr: 5622DAA0F010" t2.doTest(); // Prints "Address of arr: 5622DAA0F010" t3.doTest(); // Prints "Address of arr: null" }
Jan 21 2019
On Tuesday, 22 January 2019 at 03:30:34 UTC, Meta wrote:You're printing the address of the object reference, not the object itself (similar to printing the address of a pointer instead of the actual address it points to). Do `cast(void*)c` instead.Doh! Thanks.
Jan 22 2019
On Tue, 22 Jan 2019 01:18:24 +0000, aliak wrote:t1.doTest(); // Prints "Address of arr: 7FFE1322A7E8" t2.doTest(); // Prints "Address of arr: 7FFE1322A7F0" t3.doTest(); // Prints "Address of arr: 7FFE1322A7F8" } t1 and t2 have different addresses and t3 has t1's address?? Huh?\E8 != F8.
Jan 21 2019
On Tuesday, 22 January 2019 at 03:36:31 UTC, Neia Neutuladh wrote:On Tue, 22 Jan 2019 01:18:24 +0000, aliak wrote:lol. True.t1.doTest(); // Prints "Address of arr: 7FFE1322A7E8" t2.doTest(); // Prints "Address of arr: 7FFE1322A7F0" t3.doTest(); // Prints "Address of arr: 7FFE1322A7F8" } t1 and t2 have different addresses and t3 has t1's address?? Huh?\E8 != F8.
Jan 22 2019
On Monday, January 21, 2019 12:08:49 PM MST Alex via Digitalmars-d wrote:On Monday, 21 January 2019 at 17:06:55 UTC, Nick Treleaven wrote:A classic case would be some uses of RAII such as what MFC does with its hourglass. You get code something like Hourglass hg; and that does everything. The constructor pops up the hourglass, and the destructor takes it down. If you wanted an object like that in D, you would have to use a factory function. e.g. auto hg = Hourglass.create(); and you would then have to make it so that the object can deal with the fact that the init value never when through the factory function and thus must do nothing in its destructor (using disable this() to disable default initialization reduces that problem, but since the init value can still be used explicitly, it really doesn't eliminate the problem). Similarly, as Meta alludes to in his example, having dynamic arrays of mutable elements as member variables is problematic with structs, because all of the instances of that struct on the same thread have a dynamic array that is a slice of the same chunk of memory, meaning that mutating an element in one mutates all of them (at least all of them which haven't ended up with their array being reallocated due to appending or whatnot). In most cases, you'd really want a separate dynamic array for each instance of the struct, and D doesn't give a good way to do that with init values, forcing you to use a factory function instead of a constructor if you want to try and force it. And now that we can actually directly initialize member variables which are pointers or class references, those join the ranks of potentially having problems due to all of the instances of that struct on a particular thread having the same value for those pointers or references. So, it can become a bit error-prone for those types of member variables. And really, any and all situations where you're looking to have a piece of code run when an instance of the struct is created but where you don't necessarily have arguments for the constructor is going to be harder to deal with cleanly in D thanks to the lack of default constructors. In general, you just learn to live with it and use factory functions to deal with the problem in those cases where it pops up. So, it usually isn't a big deal, and it's mostly just something that folks new to D complain about, but having init values such that we cannot have default constructors for structs is an area in D that's a tradeoff, not a complete win. Many of us think that the tradeoffs involved are well worth it, but that doesn't change the fact that there are times when having a default constructor would be really nice, and the fact that you can't is then annoying. - Jonathan M DavisOn Saturday, 19 January 2019 at 11:01:14 UTC, Alex wrote:Could you give an example, where a zero argument construction has to be done, which cannot be accomplished by setting the appropriate field with a default value?Performance for repeated function calls after construction, we don't want an extra branch test on each function call and an extra bool bloating/tainting fields in the struct. A pseudo constructor function is a workaround, but is a bit ugly, adding a separate symbol you have to check for when learning a new library struct, and the function has more unnecessary boilerplate vs a constructor.2. not everything can be set using member initializer because of CTFE limitations.Hm... ok. But even then, if something does not work in the way it should because of limitations: What prevents of setting the parameter inside a function after or on creation?Or, using a non-default constructor exactly for these params?You can't have a zero argument non-default struct constructor. I've never been told why: https://wiki.dlang.org/Language_issues#Explicit_syntax_and_.40disable_th is Only the default constructor is constrained by .init, explicit zero argument construction is unconstrained. It could be allowed.
Jan 21 2019
On Monday, 21 January 2019 at 22:48:41 UTC, Jonathan M Davis wrote:A classic case would be some uses of RAII such as what MFC does with its hourglass. You get code something like Hourglass hg; and that does everything. The constructor pops up the hourglass, and the destructor takes it down. If you wanted an object like that in D, you would have to use a factory function. e.g. auto hg = Hourglass.create(); and you would then have to make it so that the object can deal with the fact that the init value never when through the factory function and thus must do nothing in its destructor (using disable this() to disable default initialization reduces that problem, but since the init value can still be used explicitly, it really doesn't eliminate the problem). Similarly, as Meta alludes to in his example, having dynamic arrays of mutable elements as member variables is problematic with structs, because all of the instances of that struct on the same thread have a dynamic array that is a slice of the same chunk of memory, meaning that mutating an element in one mutates all of them (at least all of them which haven't ended up with their array being reallocated due to appending or whatnot).Ah!!In most cases, you'd really want a separate dynamic array for each instance of the struct, and D doesn't give a good way to do that with init values, forcing you to use a factory function instead of a constructor if you want to try and force it. And now that we can actually directly initialize member variables which are pointers or class references, those join the ranks of potentially having problems due to all of the instances of that struct on a particular thread having the same value for those pointers or references. So, it can become a bit error-prone for those types of member variables. And really, any and all situations where you're looking to have a piece of code run when an instance of the struct is created but where you don't necessarily have arguments for the constructor is going to be harder to deal with cleanly in D thanks to the lack of default constructors. In general, you just learn to live with it and use factory functions to deal with the problem in those cases where it pops up. So, it usually isn't a big deal, and it's mostly just something that folks new to D complain about, but having init values such that we cannot have default constructors for structs is an area in D that's a tradeoff, not a complete win. Many of us think that the tradeoffs involved are well worth it, but that doesn't change the fact that there are times when having a default constructor would be really nice, and the fact that you can't is then annoying.Ok... see it now...
Jan 21 2019
On Saturday, January 19, 2019 3:05:22 AM MST Dru via Digitalmars-d wrote:What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxStructs in D don't actually have default constructors. Rather, they have a default value that they're initialized to - namely T.init (where T is the type name). In fact, all types in D have a default value so that they're guaranteed to not be garbage if you forget to initialize them with a specific value. This gets taken advantage of in a number of places. One obvious one is arrays. The init value can simply be blitted into all of the elements of the array. A number of features in D are built around that and really don't work without it. In fact, if you disable this() to disable default-initialization, it makes it so that you can't do a number of things with that type that you can normally do (e.g. put it in an array), because those language features require default-initialization. In fact, default values are so critical in D that a struct with disable this() still has an init value (e.g. it's used to initialize the struct before the constructor is called). It's just that you can't use the struct in places where default initialization is required, because you told the compiler that you didn't want that to be allowed. However, code may still explicitly use the init value, and some functions will use it (e.g move uses it to ensure that the memory that's left behind after the move isn't in a garbage state). So, while disable this _can_ be useful, it tends to just be begging for problems, because D is very much designed with the idea that everything can be default-initialized, and disable this() was only really added as a hack for rare cases where you really needed to not have something be default-initialized. If you really need something akin to a default constructor, then the normal thing to do is to use a factory function, not do something funky like have dummy arguments. And it may be appropriate in such a situation to disable this() so that you don't end up with the object being default-initialized (theoretically forcing folks to use the factory function), but even then, there are cases where the init value may still get used, so relying on it never being used can be problematic. And yes, sometimes, the fact that you can't have default constructors on structs in D like you would in C++ can be annoying, but it's a consequence of the fact that D insists on not having types created with garbage values (as frequently happens in C/C++), and the rest of the language was then built with the assumption that everything is default-initialized. So, while it can be annoying, it does prevent a whole class of bugs that are common in other languages. All of the various ways around it were added later and are used at your own risk. Alternatively, unlike structs, because classes are reference types (and thus default-initialized to null), they are able to have default constructors. So, if allocating your objects is fine, then classes may be a better option for whatever you're trying to do that requires a default constructor. Or they may not - that would depend on what the code needs to do - but it's something to consider. - Jonathan M Davis
Jan 19 2019
On Saturday, 19 January 2019 at 11:13:22 UTC, Jonathan M Davis wrote:On Saturday, January 19, 2019 3:05:22 AM MST Dru via Digitalmars-d wrote:I've always wondered why T.init can't be it's own thing and separate from this(). So if someone defined a this() then D just treats it like a custom non-default constructor? Not possible?What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxStructs in D don't actually have default constructors. Rather, they have a default value that they're initialized to - namely T.init (where T is the type name). In fact, all types in D have a default value so that they're guaranteed to not be garbage if you forget to initialize them with a specific value. This gets taken advantage of in a number of places. One obvious one is arrays. The init value can simply be blitted into all of the elements of the array. A number of features in D are built around that and really don't work without it.
Jan 21 2019
On Monday, January 21, 2019 6:23:21 PM MST aliak via Digitalmars-d wrote:On Saturday, 19 January 2019 at 11:13:22 UTC, Jonathan M Davis wrote:If D allowed struct's to have a constructor without any parameters, it would not be and could not be a default constructor because of how init works. It would only be a constructor that was called when used explicitly. As such, it wouldn't really add much over just using a factory function, and it would run a serious risk of confusing people, because newcomers would expect this() to be a default constructor when it wasn't. It also would be bad for porting code to D from languages like C++, because without extra work from the programmer, the code would assume that this() was a default constructor when it wasn't, making it easy to end up with subtle bugs. By outright making this() illegal, D forces the programmer to deal with the situation rather than allowing silent bugs. If it hadn't, I can guarantee that there would have been tons of confusion and complaints over how this() wasn't working correctly, because everyone coming to D would expect it to be a default constructor and then be very confused when it wasn't being called in code like Foo foo; or auto arr = new Foo[](42); The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects. But aside from that, a factory function is just as good as a constructor, and it doesn't carry with it the confusion of whether this() is a default constructor or not. - Jonathan M DavisOn Saturday, January 19, 2019 3:05:22 AM MST Dru via Digitalmars-d wrote:I've always wondered why T.init can't be it's own thing and separate from this(). So if someone defined a this() then D just treats it like a custom non-default constructor? Not possible?What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxStructs in D don't actually have default constructors. Rather, they have a default value that they're initialized to - namely T.init (where T is the type name). In fact, all types in D have a default value so that they're guaranteed to not be garbage if you forget to initialize them with a specific value. This gets taken advantage of in a number of places. One obvious one is arrays. The init value can simply be blitted into all of the elements of the array. A number of features in D are built around that and really don't work without it.
Jan 21 2019
If D allowed struct's to have a constructor without any parameters, it would not be and could not be a default constructor because of how init works. It would only be a constructor that was called when used explicitly.the problem is construction of static variables right? we could allow to define a default ctor and then give an error in case it is used for a static variable. A a; //would error if A has a runtime default ctor these would still work: A a = A.init; A a = void;
Jan 22 2019
On Tuesday, January 22, 2019 2:38:41 PM MST Dru via Digitalmars-d wrote:It's far from just static variables. For instance, init is a core part of how arrays are initialized. You can't even put something in an array if default initialization is disabled for that type. The language in general assumes that everything is default-initialized, and when it can't be, you start running running into stray places where you can't do stuff that you can normally do. Introducing any kind of default construction to structs would be a massive shift, and I doubt that I could come up with all of the stuff that would be affected off the top of my head. - Jonathan M DavisIf D allowed struct's to have a constructor without any parameters, it would not be and could not be a default constructor because of how init works. It would only be a constructor that was called when used explicitly.the problem is construction of static variables right? we could allow to define a default ctor and then give an error in case it is used for a static variable. A a; //would error if A has a runtime default ctor these would still work: A a = A.init; A a = void;
Jan 23 2019
On Tuesday, 22 January 2019 at 02:18:37 UTC, Jonathan M Davis wrote:It also would be bad for porting code to D from languages like C++, because without extra work from the programmer, the code would assume that this() was a default constructor when it wasn't, making it easy to end up with subtle bugs. By outright making this() illegal, D forces the programmer to deal with the situation rather than allowing silent bugs.D could solve this by only allowing a nullary constructor when there's ` disable this();`. The fact that ` disable this()` exists undermines the reason for a blanket ban on `this(){...}`, and I expect it's this way just because disable this was added later. This is worth having and would support Mutex, HourGlass, etc. Besides runtime immutable initialization not working in a free function 'constructor' as you mentioned, not allowing a nullary constructor breaks the variadic constructor pattern in generic code when no arguments are passed.
Jan 31 2019
On Thursday, January 31, 2019 4:42:35 AM MST Nick Treleaven via Digitalmars- d wrote:On Tuesday, 22 January 2019 at 02:18:37 UTC, Jonathan M Davis wrote:The main problem with allowing a constructor with no parameters when you disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. To make it work, you'd have to start making stuff work one way with init normally and another way when disable this() was present, which would be confusing and likely error-prone. And yes, the issues with disable this(); stem from the fact that it was shoehorned into the language later. D was very much designed around the idea that all types are always default initialized, and any attempt to work around that starts causing problems. disable this(); is rather similar to = void; in that regard. There are cases where it makes sense to use them, but you need to know what you're doing, and their use should be quite rare. They're basically backdoors to force the language to do something that it's really not designed to do. Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine. AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with disable this(); that does not take the init value into account can cause bugs. But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an safe manner. - Jonathan M DavisIt also would be bad for porting code to D from languages like C++, because without extra work from the programmer, the code would assume that this() was a default constructor when it wasn't, making it easy to end up with subtle bugs. By outright making this() illegal, D forces the programmer to deal with the situation rather than allowing silent bugs.D could solve this by only allowing a nullary constructor when there's ` disable this();`. The fact that ` disable this()` exists undermines the reason for a blanket ban on `this(){...}`, and I expect it's this way just because disable this was added later. This is worth having and would support Mutex, HourGlass, etc. Besides runtime immutable initialization not working in a free function 'constructor' as you mentioned, not allowing a nullary constructor breaks the variadic constructor pattern in generic code when no arguments are passed.
Jan 31 2019
On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis wrote:The main problem with allowing a constructor with no parameters when you disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. ToI'm not asking for a default constructor, only an explicit nullary argument ctor.Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.Have you changed your opinion? You said only that "in some situations" casts can be used: "The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with disable this(); that does not take the init value into account can cause bugs.struct S { static disable S init; ...But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an safe manner.This is a significant downside, you can't have a safe struct that requires runtime calls for its construction but no arguments.
Feb 07 2019
On Thursday, 7 February 2019 at 11:14:47 UTC, Nick Treleaven wrote:On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis wrote:It seems to me that the only argument I've heard to not allow default construction is because people will get confused as to why array initialization doesn't use the constructor, and maybe some other cases. But, at the same time, the difference between construction and initialization is a said to be a "core concept" of D. So this seems quite reasonably solved with some documentation and just being more explicit about the separation between construction and initialization? It certainly beat the (exaggerated) weekly forum posts asking for default struct construction and why it's not allowed (speaking of confusing people) :) Cheers, - AliThe main problem with allowing a constructor with no parameters when you disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. ToI'm not asking for a default constructor, only an explicit nullary argument ctor.Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.Have you changed your opinion? You said only that "in some situations" casts can be used: "The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with disable this(); that does not take the init value into account can cause bugs.struct S { static disable S init; ...But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an safe manner.This is a significant downside, you can't have a safe struct that requires runtime calls for its construction but no arguments.
Feb 07 2019
On Thursday, February 7, 2019 4:14:47 AM MST Nick Treleaven via Digitalmars- d wrote:On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis wrote:At the moment, the only situations that I can think of where casting to immutable would not work are actually situations where you couldn't use a constructor anyway. The problem is that you can't cast data that's not guaranteed to be unique to immutable, or you risk violating the type system. With a constructor that did no casting, that would mean that you could only accept data that was either immutable or implicitly convertible to immutable. Anything else wouldn't compile. So, to get around that, you would have to cast just like you'd need to do with a factory function, and you'd then be at risk of violating the type system whenever the data was not actually unique. Because the factory function would have to cast, the programmer would have to be more careful about making sure that they didn't cast anything that wasn't guaranteed to be unique (whereas in a constructor with no casts, you wouldn't have to worry about that), so it's trusted and riskier, but it works so long as you're appropriately careful. Having a pure factory function would potentially fix the need for casting, but if you're trying to create a default constructor, odds are that it can't be pure anyway. If it could, then it's almost guaranteed that you could just put everything in the init value and not need a constructor - though there are some situations where that still wouldn't work - e.g. initializing a member variable that was an AA (since AA's don't currently travel from compile time to runtime) or when you wanted a dynamic array with known values but where each instance of the struct gets a dynamic array referring to unique memory rather than all instances sharing the same memory like you get with the init value.The main problem with allowing a constructor with no parameters when you disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. ToI'm not asking for a default constructor, only an explicit nullary argument ctor.Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.Have you changed your opinion? You said only that "in some situations" casts can be used: "The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."I'm surprised that you can do that at the moment. I thought that that was at least deprecated by now. TypeInfo was specifically fixed a while back so that it didn't have an init function so that we could deprecate the ability to declare any kind of override for init, because allowing it causes problems. One example is that it causes serious problems with metaprogramming, because init is _the_ reliable way to get your hands on an instance of a type. It was quite purposefully the case that disable this(); had no effect on the ability to reference this, because too much relies on being able to access it. Trying to make it so that you cannot rely on init existing would be extremely disruptive. Now, even then, disabling init doesn't actually get rid of the init value. It's still there and used to do stuff like initialize the struct prior to the constructor being called. Also, interestingly, I just tried struct S { disable this(); static disable S init; } and it won't compile, because that init variable uses default initialization. That can be gotten around be declaring something like static disable S init(); instead, but really, trying to get around the fact that types have init values in D is like trying to plug holes in a cheese grater. Anyone who wants to try to add default constructors to D is free to create a DIP to do so, but I expect that anyone who attempted it would have a serious battle ahead of them. You would need an extremely good understanding of exactly how the init value works and everywhere that it is used and why to even attempt to come up with a proposal to inject default constructors that would work (assuming that it's even possible to make init and default constructors interact in a sane manner). And even assuming that you had the appropriate technical knowledge to correctly indicate exactly how default constructors would work to be able to integrate with the existing language, I expect that convincing Walter and Andrei that it was worth it would not be an easy task.AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with disable this(); that does not take the init value into account can cause bugs.struct S { static disable S init; ...It could be trusted. It's just that it's up to the programmer to verify it. And sure, that's not ideal, but safe can't be used everywhere without the programmer having to deal with trusted to make it work occasionally, and we're talking about a pretty niche situation here with trying to have something similar to a default constructor for an immutable object. Regardless, with how D relies on init, that's just the way that it is. - Jonathan M DavisBut all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an safe manner.This is a significant downside, you can't have a safe struct that requires runtime calls for its construction but no arguments.
Feb 08 2019
On Saturday, 19 January 2019 at 10:05:22 UTC, Dru wrote:What is the idea behind why we can't define default ctor for structs? In current situation I need to " disable this()" then define a constructor with dummy arguments (because my constructor does not need arguments) It is a big pain on syntaxShort answer: make T.init a value, and have your destructor be able to deal with T.init
Jan 23 2019
On Wednesday, 23 January 2019 at 13:02:43 UTC, Guillaume Piolat wrote:make T.init a valueErratum: a _valid_ value
Jan 23 2019