digitalmars.dip.ideas - Allow struct constructors with all parameters optional
- Ogi (42/42) Aug 27 It is valid to overload a function with all parameters optional
- IchorDev (5/9) Aug 27 I can’t remember exactly what the reasons for that were, but I
- Ogi (39/44) Aug 28 The reasons are that, AFAIK, language designers decided that `S
- Lance Bachmeier (33/47) Aug 28 I'll point out that you can already write a library that makes
- Ogi (5/6) Aug 29 This proposal is not about allowing default struct constructors.
- Lance Bachmeier (4/15) Aug 29 My example shows that it *is* valid, but only if you jump through
- Lance Bachmeier (4/6) Aug 29 I don't mean valid, I mean you can already write code that is
- ryuukk_ (7/55) Aug 29 Are you seriously telling people to write a library to be able to
- Ogi (3/5) Aug 29 Real yakuza use `static opCall`.
- Lance Bachmeier (7/12) Aug 29 I'm saying the opposite. An intermediate-level D programmer can
- IchorDev (7/9) Aug 29 Since when did C99 have struct constructors? You can have a
- ryuukk_ (9/21) Aug 29 i didn't say a constructor, this whole thread is the result of D
- Quirin Schroll (38/47) Sep 05 I don’t know if I like it or hate it. In contrast to the other
It is valid to overload a function with all parameters optional with a function that takes no parameters. The parameterless overload is called if no arguments are passed: ```D import std.stdio; void fun(int x = 0, int y = 0) { writeln(i"fun($(x), $(y))"); } void fun() { writeln("fun()"); } fun(y:42); // fun(0, 42) fun(); // fun() ``` Same rules apply to class constructors: ```D import std.stdio; class C { this(int x = 0, int y = 0) { writeln(i"C($(x), $(y))"); } this() { writeln("C()"); } } auto c1 = new C(y:42); // C(0, 42) auto c2 = new C(); // C() ``` D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid: ```D struct S { this(int x = 0, int y = 0) { writeln(i"S($(x), $(y))"); } } auto s1 = S(y:42); // S(0, 42) auto s2 = S(); // default initialization ```
Aug 27
On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much senseI can’t remember exactly what the reasons for that were, but I thought those reasons applied equally to any constructors that *could* be called with 0 parameters? Could you also elaborate about how named parameters affect this situation?
Aug 27
On Tuesday, 27 August 2024 at 22:53:45 UTC, IchorDev wrote:I can’t remember exactly what the reasons for that were, but I thought those reasons applied equally to any constructors that *could* be called with 0 parameters?The reasons are that, AFAIK, language designers decided that `S s` and `auto s = S()` producing different results would be too confusing. Speaking of constructors that could be called with zero parameters. All kinds of variadic constructors are perfectly fine, despite the fact that regular variadic functions can be called with zero parameters: ```D struct A { this(Args...)(Args) { writeln("ctor"); } } struct B { this(...) { writeln("ctor"); } } struct C { this(int[]...) { writeln("ctor"); } } struct D { this(Object...) { writeln("ctor"); } } ``` All these structs are default-initialized with zero arguments and call their constructor with non-zero number of arguments. Exactly how I expect a constructor with all optional parameters to behave.Could you also elaborate about how named parameters affect this situation?Consider this function: ``` void fun(int a = 0, int b = 0, int c = 0) ``` Before introduction of named arguments it wasn’t possible to call `fun` by only passing `c`. You had to pass all preceding arguments as well: `fun(0, 0, 42)`. So even if you could define a struct constructor with all optional parameters, this wouldn’t make any difference. You always had to pass at least the first argument anyway. Nowadays, thanks to named arguments, you actually can call `fun` by only passing `c`: `fun(c:42)`. With this change struct constructors with all optional parameters became useful, but they are still prohibited.
Aug 28
On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid: ```D struct S { this(int x = 0, int y = 0) { writeln(i"S($(x), $(y))"); } } auto s1 = S(y:42); // S(0, 42) auto s2 = S(); // default initialization ```I'll point out that you can already write a library that makes your code run. I'd like a way to do it directly without jumping through these hoops. foo.d: ``` import std; struct S { this(int x, int y = 0) { writeln(i"S($(x), $(y))"); } } ``` bar.d: ``` import foo; alias _S = foo.S; _S S() { return _S(0, 0); } ``` baz.d: ``` public import foo, bar; alias S = bar.S; ``` call.d: ``` import baz; void main() { auto s2 = S(); } ```
Aug 28
On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:…This proposal is not about allowing default struct constructors. Under this proposal, `S()` would still be initialized with `S.init`.
Aug 29
On Thursday, 29 August 2024 at 09:37:53 UTC, Ogi wrote:On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:I'm not sure I understand. This is what you wrote:…This proposal is not about allowing default struct constructors. Under this proposal, `S()` would still be initialized with `S.init`.D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid:My example shows that it *is* valid, but only if you jump through unnecessary hoops.
Aug 29
On Thursday, 29 August 2024 at 13:20:04 UTC, Lance Bachmeier wrote:My example shows that it *is* valid, but only if you jump through unnecessary hoops.I don't mean valid, I mean you can already write code that is equivalent to the caller.
Aug 29
On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:Are you seriously telling people to write a library to be able to do what C already provides for decades? This is why nobody takes D seriously, all that code just to initialize a struct Unbelievable, seriouslyD disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid: ```D struct S { this(int x = 0, int y = 0) { writeln(i"S($(x), $(y))"); } } auto s1 = S(y:42); // S(0, 42) auto s2 = S(); // default initialization ```I'll point out that you can already write a library that makes your code run. I'd like a way to do it directly without jumping through these hoops. foo.d: ``` import std; struct S { this(int x, int y = 0) { writeln(i"S($(x), $(y))"); } } ``` bar.d: ``` import foo; alias _S = foo.S; _S S() { return _S(0, 0); } ``` baz.d: ``` public import foo, bar; alias S = bar.S; ``` call.d: ``` import baz; void main() { auto s2 = S(); } ```
Aug 29
On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:Are you seriously telling people to write a library to be able to do what C already provides for decades?Real yakuza use `static opCall`. (I’m kidding. Don’t use `opCall`, kids)
Aug 29
On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:Are you seriously telling people to write a library to be able to do what C already provides for decades? This is why nobody takes D seriously, all that code just to initialize a struct Unbelievable, seriouslyI'm saying the opposite. An intermediate-level D programmer can use modules and aliases in a straightforward way to accomplish the same thing, even on a third-party library that someone else wrote and that you don't want to change. The restriction isn't actually a restriction but an annoyance. It should be possible to do this within the struct itself.
Aug 29
On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:Are you seriously telling people to write a library to be able to do what C already provides for decades?Since when did C99 have struct constructors? You can have a factory function in both languages, and they are the preferred method for ‘default construction’. However, in C you can’t ` disable this()`, so you have to trust the user to get it right by calling your factory function instead of just creating an uninitialised struct variable.
Aug 29
On Thursday, 29 August 2024 at 20:29:22 UTC, IchorDev wrote:On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:i didn't say a constructor, this whole thread is the result of D not having the foundation right Allow this: ```D my_fun( Data { c: 1 } ); ``` And you don't need all of that extra shitAre you seriously telling people to write a library to be able to do what C already provides for decades?Since when did C99 have struct constructors? You can have a factory function in both languages, and they are the preferred method for ‘default construction’. However, in C you can’t ` disable this()`, so you have to trust the user to get it right by calling your factory function instead of just creating an uninitialised struct variable.However, in C you can’t ` disable this()`, so you have to trust the user to get it right by calling your factory function instead of just creating an uninitialised struct variable.lol, no, reject bloat, and stick to simplicity
Aug 29
On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:```D struct S { this(int x = 0, int y = 0) { writeln(i"S($(x), $(y))"); } } auto s1 = S(y: 42); // S(0, 42) auto s2 = S(); // default initialization ```I don’t know if I like it or hate it. In contrast to the other ones, the nullary overload is visually present, whereas here, it’s not. Not being able to use the constructor with one or both arguments explicitly because you just aren’t allowed to define it is annoying, 100%. Working around that is possible, though: ```d safe: import std.stdio; struct S { private enum Y { _ } this(int x, int y = 0) { writeln(i"S($(x), $(y))"); } this(Y = Y.init, int y) { this(0, y); } } void main() { auto s = [ S(42), S(x: 42), S(y: 42), S(1, 2), S() ]; // prints: S(42, 0), S(42, 0), S(0, 42), S(1, 2) // absent: S(0, 0) } ``` The `Y = Y.init` makes the overload viable only through named arguments, so that `S(y: 42)` is possible. I’d be definitely in favor of it if the proposal included defining and defaulting the nullary constructor, which would be required in this case. Something like that: ```d struct S { default this(); // new this(int x = 0, int y = 0) { writeln(i"S($(x), $(y))"); } } ``` The nullary constructor can be ` disable`d, so making it also special in it being able to be `default`ed doesn’t really make difference.
Sep 05