digitalmars.D - Struct Initialization syntax
- Seb (23/23) Jul 23 2018 tl;dr: the currently proposed syntax options are:
- =?UTF-8?B?THXDrXM=?= Marques (6/9) Jul 23 2018 Although a bit more verbose that seems like a good choice. If you
- H. S. Teoh (26/47) Jul 23 2018 Yeah.
- aliak (17/20) Jul 23 2018 After using Swift for a while, I've found this to be the exact
- H. S. Teoh (18/41) Jul 23 2018 [...]
- aliak (5/21) Jul 23 2018 Hehe oops, indeed you were :p Seems I did not parse properly.
- =?UTF-8?B?THXDrXM=?= Marques (3/4) Jul 23 2018 If such integration was possible then that sounds like it would
- kinke (2/7) Jul 23 2018 +1. And hoping for the latter, seamless consistency.
- rikki cattermole (4/13) Jul 23 2018 Based upon my DIP that is in the queue for named arguments, it would be
- Daniel N (3/17) Jul 24 2018 Yes, it makes sense to review the "named arguments" DIP before
- rikki cattermole (8/27) Jul 24 2018 Mine: https://github.com/dlang/DIPs/pull/126
- John Colvin (6/34) Jul 23 2018 Seeing as we already have
- Guillaume Lathoud (6/27) Jul 24 2018 Not sure about this, but wouldn't
- Cym13 (18/41) Jul 23 2018 I'm in favour of 3.
- Cym13 (2/6) Jul 23 2018 I took that last point to GH, no need to discuss it here.
- Andre Pany (7/30) Jul 23 2018 I also prefer option 3. From a readability point of view it is
- JohnB (3/7) Jul 23 2018 +1.
- Jacob Carlborg (7/33) Jul 23 2018 Talking about future potential features, Option 1 could be in conflict
- rikki cattermole (2/36) Jul 23 2018 We ugh can't use that syntax because of ambiguity to AssignExpression.
- Dukc (7/8) Jul 24 2018 Option 2 won't necessarily cause problems with named funcion
- Cym13 (6/14) Jul 24 2018 That argument sounds quite dangerous to me, especially since my
- Dukc (13/18) Jul 24 2018 I was going to ask that how can they be named the same since the
- H. S. Teoh (10/32) Jul 24 2018 It works, but TBH it's quite a bad idea, and very confusing to read.
- Jim Balter (24/57) Jul 25 2018 This is a very common programming style and is found in numerous
- Neia Neutuladh (25/30) Jul 24 2018 If we have named arguments that can be reordered and, when they
- rikki cattermole (4/7) Jul 24 2018 It actually doesn't surprisingly.
tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done. I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this? DIP: https://github.com/dlang/DIPs/pull/71 Rendered view: https://github.com/wilzbach/DIPs/blob/struct-initialization/DIPs/DIP1xxx-sw.md
Jul 23 2018
On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this?Although a bit more verbose that seems like a good choice. If you could save the “initialization list” in an enum that choice also seems to generalize better. Not conflicting with named arguments is important for me, as named arguments would be very nice to have for hardware description kind of stuff.
Jul 23 2018
On Mon, Jul 23, 2018 at 04:26:42PM +0000, Seb via Digitalmars-d wrote:tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done.+1.I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too.Yeah.Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this?[...] I don't like option 1 because it resembles anonymous function syntax and AA initialization syntax, but is actually neither. I'm on the fence about option 2 and option 3. I actually prefer option 3 as being overtly special initialization syntax that doesn't try to masquerade as something else. But OTOH, option 2 has a lot going for it, given that today, S(x, y, z) is the syntax for initializing struct fields in order, so one would expect that S(p: x, q: y, r: z) ought to be a natural extension of the syntax for specifying fields out-of-order (or with some fields omitted). It's true that there's potential conflict with named arguments, but IMO it's a mighty bad idea to name ctor parameters in a way that conflicts with the struct fields. Either your struct has a member named x, your ctor uses parameter names that are different from x (thus avoiding the confusion), or if your ctor also takes a parameter named x, in which case one would expect that it would initialize the member x, as opposed to a different member y. To have a ctor take a parameter named x but using it to initialize member y instead of member x, seems to be such a horrible idea that it should not be a big deal for struct initialization syntax to "conflict" with it. T -- If you want to solve a problem, you need to address its root cause, not just its symptoms. Otherwise it's like treating cancer with Tylenol...
Jul 23 2018
On Monday, 23 July 2018 at 16:57:20 UTC, H. S. Teoh wrote:It's true that there's potential conflict with named arguments, but IMO it's a mighty bad idea to name ctor parameters in a way that conflicts with the struct fields.After using Swift for a while, I've found this to be the exact opposite. It is on the contrary very common to name parameters as you would your members because they are very commonly the most intuitive names. struct Point { int x, int y; this(x: int, y: int) {} } auto p = Point(x: 3, y: 4); // what else would you name them? Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency. Cheers, - Ali
Jul 23 2018
On Mon, Jul 23, 2018 at 05:32:23PM +0000, aliak via Digitalmars-d wrote:On Monday, 23 July 2018 at 16:57:20 UTC, H. S. Teoh wrote:[...] I worded myself poorly. What I meant was that if a ctor parameter has the same name as a field, then it's obviously meant to initialize that field, so there isn't really a conflict, you're just passing the argument to the ctor instead of setting it directly to the struct. It would be a horrendously bad idea to have a ctor parameter that has the same name as a field, but is used to initialize a different field. OTOH, if you have a ctor, then one would assume that you're intentionally overriding direct initialization of fields, so you wouldn't want people to be using named initialization of fields anyway, they should be using the ctor instead. So any conflicts in this area wouldn't really be relevant.It's true that there's potential conflict with named arguments, but IMO it's a mighty bad idea to name ctor parameters in a way that conflicts with the struct fields.After using Swift for a while, I've found this to be the exact opposite. It is on the contrary very common to name parameters as you would your members because they are very commonly the most intuitive names.struct Point { int x, int y; this(x: int, y: int) {} } auto p = Point(x: 3, y: 4); // what else would you name them? Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.[...] Yes, this is what I was trying to get at. Thanks! T -- Don't modify spaghetti code unless you can eat the consequences.
Jul 23 2018
On Monday, 23 July 2018 at 17:46:12 UTC, H. S. Teoh wrote:I worded myself poorly. What I meant was that if a ctor parameter has the same name as a field, then it's obviously meant to initialize that field, so there isn't really a conflict, you're just passing the argument to the ctor instead of setting it directly to the struct. It would be a horrendously bad idea to have a ctor parameter that has the same name as a field, but is used to initialize a different field. [...]Hehe oops, indeed you were :p Seems I did not parse properly. Apologies! Cheers, - AliIf named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.[...] Yes, this is what I was trying to get at. Thanks! T
Jul 23 2018
On Monday, 23 July 2018 at 17:46:12 UTC, H. S. Teoh wrote:Yes, this is what I was trying to get at. Thanks!If such integration was possible then that sounds like it would be a good solution.
Jul 23 2018
On Monday, 23 July 2018 at 17:32:23 UTC, aliak wrote:Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.+1. And hoping for the latter, seamless consistency.
Jul 23 2018
On 24/07/2018 6:43 AM, kinke wrote:On Monday, 23 July 2018 at 17:32:23 UTC, aliak wrote:Based upon my DIP that is in the queue for named arguments, it would be trivial for this DIP to make it so a named parameter constructor can override the default behavior and I think that this is the best way forward.Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.+1. And hoping for the latter, seamless consistency.
Jul 23 2018
On Tuesday, 24 July 2018 at 03:59:53 UTC, rikki cattermole wrote:On 24/07/2018 6:43 AM, kinke wrote:Yes, it makes sense to review the "named arguments" DIP before this one, any link?On Monday, 23 July 2018 at 17:32:23 UTC, aliak wrote:Based upon my DIP that is in the queue for named arguments, it would be trivial for this DIP to make it so a named parameter constructor can override the default behavior and I think that this is the best way forward.Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.+1. And hoping for the latter, seamless consistency.
Jul 24 2018
On 24/07/2018 7:23 PM, Daniel N wrote:On Tuesday, 24 July 2018 at 03:59:53 UTC, rikki cattermole wrote:Mine: https://github.com/dlang/DIPs/pull/126 Yshui's: https://github.com/dlang/DIPs/pull/123 Mine is a lot heavier-weight, and applies to templates parameters as well as functions. Where as Yshui's is very lightweight compared and only applies to functions. Yshui's will occur first I think, but really we should review them together to decide what sort of approach is best.On 24/07/2018 6:43 AM, kinke wrote:Yes, it makes sense to review the "named arguments" DIP before this one, any link?On Monday, 23 July 2018 at 17:32:23 UTC, aliak wrote:Based upon my DIP that is in the queue for named arguments, it would be trivial for this DIP to make it so a named parameter constructor can override the default behavior and I think that this is the best way forward.Can we just consider that named struct init syntax *is* a generated named constructor? If named arguments choose a different syntax then you have no conflict. If they go with the same (i.e. option 2) then you have seamless consistency.+1. And hoping for the latter, seamless consistency.
Jul 24 2018
On Monday, 23 July 2018 at 16:57:20 UTC, H. S. Teoh wrote:On Mon, Jul 23, 2018 at 04:26:42PM +0000, Seb via Digitalmars-d wrote:Seeing as we already have S s = { c : 10 }; I'd say it would be fairer to say it resembles anonymous function syntax and AA initialisation syntax, but mostly it resembles the existing struct initialisation syntax.tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done.+1.I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too.Yeah.Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this?[...] I don't like option 1 because it resembles anonymous function syntax and AA initialization syntax, but is actually neither.
Jul 23 2018
On Monday, 23 July 2018 at 18:31:03 UTC, John Colvin wrote:On Monday, 23 July 2018 at 16:57:20 UTC, H. S. Teoh wrote:Not sure about this, but wouldn't bar({c: 10}); be consistent with S s = { c : 10 }; ?On Mon, Jul 23, 2018 at 04:26:42PM +0000, Seb via Digitalmars-d wrote:... Seeing as we already have S s = { c : 10 }; I'd say it would be fairer to say it resembles anonymous function syntax and AA initialisation syntax, but mostly it resembles the existing struct initialisation syntax.tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 }
Jul 24 2018
On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done. I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this? DIP: https://github.com/dlang/DIPs/pull/71 Rendered view: https://github.com/wilzbach/DIPs/blob/struct-initialization/DIPs/DIP1xxx-sw.mdI'm in favour of 3. Option 2 looks nice but I'm against it because of possible named arguments. Even though they're not part of the language yet and may never be we already have too many clunky things not to avoid a conflict when we can. Option 1 is clean but a bit strange, I don't like the idea of doubling the enclosing symbols, in that situation you'd expect S() and {} to have separate effects, not to combine into a special effect. It also looks like a constructor while it's not, which isn't a nice conflation to make. I wouldn't be very dismayed by it though. Still, that's why I prefer option 3 which is very similar to classical struct initialization and has clearly only one effect. PS: Now that I think about it, would something like S{c:3}("a") be allowed to say “Call the constructor with the string "a" as argument on the struct of type S initialized with c=3”? I may have missed it but I don't think that's addressed by the DIP.
Jul 23 2018
On Monday, 23 July 2018 at 17:10:08 UTC, Cym13 wrote:PS: Now that I think about it, would something like S{c:3}("a") be allowed to say “Call the constructor with the string "a" as argument on the struct of type S initialized with c=3”? I may have missed it but I don't think that's addressed by the DIP.I took that last point to GH, no need to discuss it here.
Jul 23 2018
On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done. I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this? DIP: https://github.com/dlang/DIPs/pull/71 Rendered view: https://github.com/wilzbach/DIPs/blob/struct-initialization/DIPs/DIP1xxx-sw.mdI also prefer option 3. From a readability point of view it is the most pleasant one (my personal opinion). I also like it due to the already existing struct initialization syntax I am using a lot. Kind regards Andre
Jul 23 2018
On Monday, 23 July 2018 at 18:02:04 UTC, Andre Pany wrote:I also prefer option 3. From a readability point of view it is the most pleasant one (my personal opinion). I also like it due to the already existing struct initialization syntax I am using a lot.+1. JohnB.
Jul 23 2018
On 2018-07-23 18:26, Seb wrote:tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done. I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this? DIP: https://github.com/dlang/DIPs/pull/71 Rendered view: https://github.com/wilzbach/DIPs/blob/struct-initialization/DIPs/DIP1xxx-sw.mdTalking about future potential features, Option 1 could be in conflict with a tuple with named elements. Option 2 could be in conflict with named parameters, true, but named parameters could also have a different syntax, i.e. foo(a = 3, b = 4), this is what Scala is using. -- /Jacob Carlborg
Jul 23 2018
On 24/07/2018 7:11 AM, Jacob Carlborg wrote:On 2018-07-23 18:26, Seb wrote:We ugh can't use that syntax because of ambiguity to AssignExpression.tl;dr: the currently proposed syntax options are: --- struct S { int a = 2, b = 4, c = 6; } void foo() { bar(S({c: 10})); // Option 1 bar(S(c: 10)); // Option 2 bar(S{c: 10}); // Option 3 } --- So the struct-initialization DIP has been stalled for too long and I think it's time we finally get this story done. I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this? DIP: https://github.com/dlang/DIPs/pull/71 Rendered view: https://github.com/wilzbach/DIPs/blob/struct-initialization/DIPs/DIP1xxx-sw.mdTalking about future potential features, Option 1 could be in conflict with a tuple with named elements. Option 2 could be in conflict with named parameters, true, but named parameters could also have a different syntax, i.e. foo(a = 3, b = 4), this is what Scala is using.
Jul 23 2018
On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:What's your take on this?Option 2 won't necessarily cause problems with named funcion arguments: The names of the constructor arguments and members are different anyway, at least usually, letting the compiler to infer the intended call by them. But there might be some corner cases where this would not apply. Do you see any?
Jul 24 2018
On Tuesday, 24 July 2018 at 10:48:40 UTC, Dukc wrote:On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:That argument sounds quite dangerous to me, especially since my experience is on the contrary that constructor arguments are often named the same as the attribute they refer to. And what of mixed cases? I really wouldn't rely on anything like naming conventions for something like that.What's your take on this?Option 2 won't necessarily cause problems with named funcion arguments: The names of the constructor arguments and members are different anyway, at least usually, letting the compiler to infer the intended call by them. But there might be some corner cases where this would not apply. Do you see any?
Jul 24 2018
On Tuesday, 24 July 2018 at 12:37:21 UTC, Cym13 wrote:That argument sounds quite dangerous to me, especially since my experience is on the contrary that constructor arguments are often named the same as the attribute they refer to. And what of mixed cases? I really wouldn't rely on anything like naming conventions for something like that.I was going to ask that how can they be named the same since the argument would then shadow the member, but then I realized that this works: struct S { int a; int b; this(int a, int b) { this.a = a; this.b = b; } } Yes, you are right.
Jul 24 2018
On Tue, Jul 24, 2018 at 01:13:16PM +0000, Dukc via Digitalmars-d wrote:On Tuesday, 24 July 2018 at 12:37:21 UTC, Cym13 wrote:It works, but TBH it's quite a bad idea, and very confusing to read. And TBH, if all the ctor is doing is copying its arguments to member variables, then we really should be more DRY and have special syntax for doing that, ala C++ (though the C++ syntax itself is pretty pathological... D could use better syntax, but the idea remains: get rid of redundancy like `this.a = a` or `a = _a`). T -- Старый друг лучше новых двух.That argument sounds quite dangerous to me, especially since my experience is on the contrary that constructor arguments are often named the same as the attribute they refer to. And what of mixed cases? I really wouldn't rely on anything like naming conventions for something like that.I was going to ask that how can they be named the same since the argument would then shadow the member, but then I realized that this works: struct S { int a; int b; this(int a, int b) { this.a = a; this.b = b; } } Yes, you are right.
Jul 24 2018
On Tuesday, 24 July 2018 at 16:35:32 UTC, H. S. Teoh wrote:On Tue, Jul 24, 2018 at 01:13:16PM +0000, Dukc via Digitalmars-d wrote:This is a very common programming style and is found in numerous programming books and tutorials. Personal judgments as to whether it's a good idea or confusing are completely beside the point; designers of struct initialization syntax should not impose such judgments on the rest of the world, possibly forcing people to change their code and their texts.On Tuesday, 24 July 2018 at 12:37:21 UTC, Cym13 wrote:It works, but TBH it's quite a bad idea, and very confusing to read.That argument sounds quite dangerous to me, especially since my experience is on the contrary that constructor arguments are often named the same as the attribute they refer to. And what of mixed cases? I really wouldn't rely on anything like naming conventions for something like that.I was going to ask that how can they be named the same since the argument would then shadow the member, but then I realized that this works: struct S { int a; int b; this(int a, int b) { this.a = a; this.b = b; } } Yes, you are right.And TBH, if all the ctor is doing is copying its arguments to member variables, then we really should be more DRY and have special syntax for doing that, ala C++ (though the C++ syntax itself is pretty pathological... D could use better syntax, but the idea remains: get rid of redundancy like `this.a = a` or `a = _a`). TThis too is completely off topic. And there are hundreds of thousands of extant lines of such code in various languages other than C++ (or Scala, which has a different and more concise way to avoid this boilerplate), and it hasn't been a big deal. Some people use IDE forms/macros to fill in these common lines. like a function or ctor call but isn't, and it looks like {...} conjunction with and dependent on named parameters. If named were a call to an implicit ctor that takes optional named parameters corresponding to each member, which would provide uniformity, but I think it's a bit dangerous and confusing, using the same syntax to do two different things, initialization and consistent with existing struct initialization ... does it have any downsides?
Jul 25 2018
On Monday, 23 July 2018 at 16:26:42 UTC, Seb wrote:I personally prefer option 2, but this might be in conflict to named arguments which we hopefully see in the near future too. Hence, I'm leaning forward to proposing Option 1 as the recommended Option for the DIP (that's also what the PoC DMD PR implements). What's your take on this?If we have named arguments that can be reordered and, when they have default values, omitted, we don't really need a special struct initialization syntax. We just need the compiler to generate the implicit struct constructor in the obvious way, like: struct S { string a = "field a!"; int b = 10; // compiler-generated this(<string a = "field a!", int b = 10>) {...} } writeln(S(a: "hello", b: 15)); Similarly, struct initializer syntax everywhere slightly reduces the need for named arguments, albeit with some inconvenience: // named args style void drawRect(<int x, int y, int width, int height, string color>) {} // struct style struct DrawRect { int x, y, width, height; string color; } void drawRect(DrawRect rect) {}
Jul 24 2018
On 25/07/2018 5:55 AM, Neia Neutuladh wrote:Similarly, struct initializer syntax everywhere slightly reduces the need for named arguments, albeit with some inconvenience:It actually doesn't surprisingly. As long as you support it for templates as well. At which point it creates a nice consistent experience.
Jul 24 2018