digitalmars.D - DIP 1031--Deprecate Brace-Style Struct Initializers--Community Review
- Mike Parker (23/23) Feb 12 2020 This is the feedback thread for the first round of Community
- Mike Parker (3/8) Feb 12 2020 The Feedback thread is here:
- Paolo Invernizzi (8/18) Feb 13 2020 It makes me a little sad to read "With the adoption of named
- Mike Parker (17/24) Feb 13 2020 Please note the DIP also says:
- Paolo Invernizzi (5/23) Feb 13 2020 Acknowledged, sorry for that ... I need to remember to take the
- Guillaume Piolat (4/6) Feb 15 2020 13 years of D and I didn't know brace-style struct initializers
- Jonathan M Davis (17/23) Feb 21 2020 I tend to forget that the syntax exists, and I never use it, but it's
- Jonathan M Davis (9/34) Feb 21 2020 Ouch. I didn't read carefully enough. I wasn't aware that the brace styl...
- Basile B. (13/16) Feb 13 2020 I'm in favor of a change. So there were two options
- IGotD- (25/25) Feb 13 2020 According to the DIP
- Walter Bright (5/27) Feb 13 2020 No. But you can write:
- Mike Parker (6/25) Feb 13 2020 Which, for the record, is the current behavior. Unfortunately,
- Steven Schveighoffer (9/38) Feb 13 2020 That page is *really* old. I think what Mike meant to say is that struct...
- IGotD- (10/19) Feb 13 2020 Isn't that a bit restrictive? Wouldn't you like to have a
- Steven Schveighoffer (17/38) Feb 13 2020 You misunderstand.
- Walter Bright (7/8) Feb 13 2020 Yes, and it's on purpose. Note that this applies to C++ as well.
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (8/18) Feb 13 2020 I never understood (but expect some good reason to exists) why I can't w...
- Basile B. (4/7) Feb 13 2020 It would only work in the context of a declaration, otherwise
- Atila Neves (3/18) Feb 13 2020 https://en.wikipedia.org/wiki/Most_vexing_parse
- Walter Bright (3/4) Feb 13 2020 Yes. There's no reason to support such things. C++ has to because it mad...
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (6/13) Feb 14 2020 As I expected... thanks for the reference.
- Petar Kirov [ZombineDev] (23/48) Feb 13 2020 This is allowed today:
- Donald (12/13) Feb 13 2020 Well first I'm not against this, but one thing that called my
- Ron Tarrant (5/6) Feb 13 2020 If I understand correctly what this change means, I've already
- neikeq (5/5) Feb 13 2020 I'm against this change unless there's a good reason other than
- Mathias Lang (48/52) Feb 13 2020 I think this is heading in the right direction, however I see
- aliak (12/58) Feb 13 2020 This seems like a hole indeed. I wonder if it's worth considering
- Mathias Lang (22/50) Feb 13 2020 The real inconvenience shows up as you nest structure, which was
- aliak (12/28) Feb 14 2020 I'm not sure I see where you're repeating types there. As for
- matheus (3/22) Feb 14 2020 Matheus.
- Thomas Brix (42/58) Feb 14 2020 Perhaps declarative programming should be a first class feature,
- Steven Schveighoffer (41/88) Feb 14 2020 This is probably less of a problem. If you need to initialize items via
- 12345swordy (7/103) Feb 14 2020 I was thinking of this when you brought up that issue.
- Steven Schveighoffer (51/59) Feb 14 2020 Hm... a possible benefit that has not been discussed, brace-style
- Steven Schveighoffer (3/4) Feb 14 2020 ugh, didn't finish this edit. Should be:
- Walter Bright (2/3) Feb 14 2020 That's why D has alias declarations.
- Steven Schveighoffer (18/23) Feb 14 2020 An alias declaration is a declaration. It needs its own line before the
- IGotD- (9/27) Feb 14 2020 Yes, typing in the type name quickly gets old for these kinds of
- Walter Bright (5/6) Feb 14 2020 It can be done inline with lambdas, like dmd itself does:
- Steven Schveighoffer (5/14) Feb 15 2020 Not sure what this is supposed to mean. I hope not:
- Walter Bright (3/4) Feb 15 2020 Generally, such things can get a lot clearer if you use better formattin...
- Walter Bright (8/12) Feb 14 2020 You can also do:
- Steven Schveighoffer (15/36) Feb 14 2020 This is less attractive than the alias, because now I'm calling a
- NX (37/37) Feb 17 2020 The following code is from actual real world:
- aliak (15/22) Feb 14 2020 I really like that.
- Jacob Carlborg (4/5) Feb 15 2020 (a: 42, b: 84) looks like a tuple with named elements to me.
- Max Samukha (7/10) Feb 15 2020 Exactly, a tuple-record hybrid. With Timon Gehr's tuple proposal
- Walter Bright (7/42) Feb 14 2020 I replied to him there.
- jxel (6/9) Feb 14 2020 Simplifying something isnt objectively better. Anyways, this is
- Walter Bright (3/4) Feb 14 2020 I know that n.g. discussions have a tendency to defend to the death a si...
- jxel (6/10) Feb 14 2020 If you have a large amount of code with nesting, yes. This is a
- Steven Schveighoffer (8/13) Feb 15 2020 From the perspective of the user, the complications in the compiler or
- rikki cattermole (16/32) Feb 15 2020 Except when the compiler ICE's out, they certainly care then.
- Steven Schveighoffer (18/41) Feb 15 2020 Sure, but it doesn't. brace-initializers have been in the language from
- jxel (8/11) Feb 15 2020 OK now let's not get too carried away. If that was even something
- Walter Bright (9/10) Feb 15 2020 Baloney.
- jxel (10/20) Feb 15 2020 No thank you, I don't eat baloney.
- Walter Bright (17/19) Feb 15 2020 There actually was one for the ARM. It wasn't completed because the pers...
- H. S. Teoh (27/34) Feb 15 2020 Yeah, I think the original criticism here was a bit ridiculous. However:
- Walter Bright (10/16) Feb 16 2020 The speed of the code generated was competitive with (and sometimes ahea...
- H. S. Teoh (40/62) Feb 16 2020 Note that I did not say the code quality of the back end is poor. I said
- bachmeier (7/11) Feb 17 2020 I don't know about you, but I spend like 99.9% of my time in the
- jxel (6/7) Feb 16 2020 They really aren't. Every time there's some sort of significant
- Walter Bright (9/11) Feb 15 2020 The complication is in the language. This affects the user:
- jxel (25/37) Feb 15 2020 You could remove quite a few features, and prevent new ones for
- Steven Schveighoffer (37/49) Feb 15 2020 All these points apply to for loops and foreach loops as well. All of
- Walter Bright (17/27) Feb 15 2020 It's the while loop that is redundant. foreach is key to writing generic...
- Paul Backus (3/9) Feb 15 2020 Source: https://dlang.org/spec/struct.html#dynamic_struct_init
- Walter Bright (2/12) Feb 17 2020 Yes, you're right. My mistake.
- John Colvin (27/52) Feb 15 2020 :(
- Aliak (3/32) Feb 15 2020 I know this statement is completely unconstuctive but
- Mathias Lang (4/13) Feb 16 2020 This (and the rest of the post) 100%.
- Petar Kirov [ZombineDev] (16/19) Feb 17 2020 I completely agree. I have several developers on my team with
- MoonlightSentinel (23/26) Feb 16 2020 Effectlively this DIP proposes simplifying the compiler - not so
- Nathan S. (2/2) Feb 16 2020 Would removing support for brace-style struct initializers
- Walter Bright (2/4) Feb 17 2020 No.
This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.md Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits... in other words, business as usual. However, if you have any specific feedback for how to improve the the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post. Just be sure to read and understand the Reviewer Guidelines before posting there: https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md The review period will end at 11:59 PM ET on February 27, or when I make a post declaring it complete. Discussion in this thread may continue beyond that point. At the end of Round 1, if further review is deemed necessary, the DIP will be scheduled for another round of Community Review. Otherwise, it will be queued for the Final Review and Formal Assessment. Please stay on topic here. I will delete posts that are completely off topic.
Feb 12 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:However, if you have any specific feedback for how to improve the the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post.The Feedback thread is here: https://forum.dlang.org/post/iywiuqqmevdghgbyrved forum.dlang.org
Feb 12 2020
On Thursday, 13 February 2020 at 07:30:49 UTC, Mike Parker wrote:On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:It makes me a little sad to read "With the adoption of named argument lists ..." I'm wondering if discussing about the opportunity or not to add a feature worths the time, as every decision seems already taken 'a priori'. Anyway, as it seems that named arguments is 'de-facto' approved, this DIP is the natural consequence, so that's fine.However, if you have any specific feedback for how to improve the the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post.The Feedback thread is here: https://forum.dlang.org/post/iywiuqqmevdghgbyrved forum.dlang.org
Feb 13 2020
On Thursday, 13 February 2020 at 08:22:19 UTC, Paolo Invernizzi wrote:It makes me a little sad to read "With the adoption of named argument lists ..." I'm wondering if discussing about the opportunity or not to add a feature worths the time, as every decision seems already taken 'a priori'. Anyway, as it seems that named arguments is 'de-facto' approved, this DIP is the natural consequence, so that's fine.Please note the DIP also says: "This DIP presumes the acceptance of DIP 1030: Named Arguments." And in an effort to preempt comments like your, I explicitly left this note in the feedback thread: "Please note that acceptance of this DIP is dependent upon acceptance of DIP 1030. If that DIP is rejected, this DIP will move into "Postponed" for an extended period to allow time for alternative named argument proposals." I should have left it here, too :-) Anyway, 1030 is likely to be accepted, but it isn't a given. Walter has pulled two of his DIPs in the past in response to community feedback, so please don't think any his DIPs is a rubber stamp. However, if it *is* accepted, then it saves time if we have both DIPs going through the review process close together. That's all this is.
Feb 13 2020
On Thursday, 13 February 2020 at 08:46:31 UTC, Mike Parker wrote:On Thursday, 13 February 2020 at 08:22:19 UTC, Paolo Invernizzi wrote:Acknowledged, sorry for that ... I need to remember to take the morning coffe before posting ... eheh Anyway, the DIP is fine, I've always hated brace-style struct initializers, let's kill them with fire.[...]Please note the DIP also says: "This DIP presumes the acceptance of DIP 1030: Named Arguments." And in an effort to preempt comments like your, I explicitly left this note in the feedback thread: "Please note that acceptance of this DIP is dependent upon acceptance of DIP 1030. If that DIP is rejected, this DIP will move into "Postponed" for an extended period to allow time for alternative named argument proposals." I should have left it here, too :-) Anyway, 1030 is likely to be accepted, but it isn't a given. Walter has pulled two of his DIPs in the past in response to community feedback, so please don't think any his DIPs is a rubber stamp. However, if it *is* accepted, then it saves time if we have both DIPs going through the review process close together. That's all this is.
Feb 13 2020
On Thursday, 13 February 2020 at 08:52:41 UTC, Paolo Invernizzi wrote:Anyway, the DIP is fine, I've always hated brace-style struct initializers, let's kill them with fire.13 years of D and I didn't know brace-style struct initializers even existed... Sounds error prone.
Feb 15 2020
On Saturday, February 15, 2020 5:50:15 AM MST Guillaume Piolat via Digitalmars-d wrote:On Thursday, 13 February 2020 at 08:52:41 UTC, Paolo Invernizzi wrote:I tend to forget that the syntax exists, and I never use it, but it's probably less error-prone than using the constructor syntax with a struct that has no constructors, since it's at least lining up the field initializers with the fields by name, meaning that if fields are added, removed, and/or rearranged over time, you won't end up with existing code initializing the wrong fields. If you use the constructor syntax with a struct that has no constructors, then it just sets the fields in order, and if you provide fewer initializers than there are fields, then the rest just get default-initialized. And while that can be fine when you first declare the struct, it can be very error-prone if the struct's fields are ever changed later, since existing code may still compile but then end up setting the wrong fields. It's why I pretty much always declare constructors for structs even if they're just POD types where all of the members are public. - Jonathan M DavisAnyway, the DIP is fine, I've always hated brace-style struct initializers, let's kill them with fire.13 years of D and I didn't know brace-style struct initializers even existed... Sounds error prone.
Feb 21 2020
On Friday, February 21, 2020 8:19:34 AM MST Jonathan M Davis via Digitalmars-d wrote:On Saturday, February 15, 2020 5:50:15 AM MST Guillaume Piolat via Digitalmars-d wrote:Ouch. I didn't read carefully enough. I wasn't aware that the brace style for struct initialization works without providing field names. That just seems redundant with the constructor syntax, and it has all of the same problems that you get with using the constructor syntax without a constructor, which is something that I'm inclined to think is bad practice due to how error-prone it can be as code is changed over time. - Jonathan M DavisOn Thursday, 13 February 2020 at 08:52:41 UTC, Paolo Invernizzi wrote:I tend to forget that the syntax exists, and I never use it, but it's probably less error-prone than using the constructor syntax with a struct that has no constructors, since it's at least lining up the field initializers with the fields by name, meaning that if fields are added, removed, and/or rearranged over time, you won't end up with existing code initializing the wrong fields. If you use the constructor syntax with a struct that has no constructors, then it just sets the fields in order, and if you provide fewer initializers than there are fields, then the rest just get default-initialized. And while that can be fine when you first declare the struct, it can be very error-prone if the struct's fields are ever changed later, since existing code may still compile but then end up setting the wrong fields. It's why I pretty much always declare constructors for structs even if they're just POD types where all of the members are public.Anyway, the DIP is fine, I've always hated brace-style struct initializers, let's kill them with fire.13 years of D and I didn't know brace-style struct initializers even existed... Sounds error prone.
Feb 21 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers":I'm in favor of a change. So there were two options 1. StructInitializers could have become StructLiterals, ie. a primary expression, i.e usable in all contexts, not only as initializer. 2. Kill them. By removing them you can now get rid of the special AST node for initializers. After the removal it will be either an array literal (so a primary), an AA literal (so a primary) or an expression, in other words always an expression. This option is also good to simplify the parser because struct literals could look like func literals without a full, arbitrarily long lookup. Nobody wrote a proposal for 1. so let it be 2. End of story from my point of view.
Feb 13 2020
According to the DIP This will be deprecated. struct S { int a, b; } S s = { 1, 2 }; // Deprecated: use S(1, 2) instead So after this DIP we would write S s = S(1, 2); instead. However, would S s = (1, 2); be allowed inferring the type? Would there be case where this type of initialization would mask the constructor of a type or vice versa? Ex. struct S { int a, b; this(int bp, int ap) { a = ap; b = bp; } } writing S s = S(1, 2); what would it pick?
Feb 13 2020
On 2/13/2020 1:47 AM, IGotD- wrote:However, would S s = (1, 2); be allowed inferring the type?No. But you can write: auto s = S(1, 2);Would there be case where this type of initialization would mask the constructor of a type or vice versa?The constructor takes precedence.struct S { int a, b; this(int bp, int ap) { a = ap; b = bp; } } writing S s = S(1, 2); what would it pick?The constructor.
Feb 13 2020
On Thursday, 13 February 2020 at 09:56:27 UTC, Walter Bright wrote:Which, for the record, is the current behavior. Unfortunately, the struct literal documentation only mentions opCall. I'll submit a PR. https://dlang.org/spec/struct.html#struct-literalWould there be case where this type of initialization would mask the constructor of a type or vice versa?The constructor takes precedence.struct S { int a, b; this(int bp, int ap) { a = ap; b = bp; } } writing S s = S(1, 2); what would it pick?The constructor.
Feb 13 2020
On 2/13/20 4:59 AM, Mike Parker wrote:On Thursday, 13 February 2020 at 09:56:27 UTC, Walter Bright wrote:That page is *really* old. I think what Mike meant to say is that struct initializers and struct literals are both disabled once a constructor or opCall function is present. So in essence, the above struct S could NEVER be initialized except via constructor or with it's .init value. Having the named parameter DIP accepted means that now the constructor becomes possible to call like the initializer, assuming you gave bp and ap default values. -SteveWhich, for the record, is the current behavior. Unfortunately, the struct literal documentation only mentions opCall. I'll submit a PR. https://dlang.org/spec/struct.html#struct-literalWould there be case where this type of initialization would mask the constructor of a type or vice versa?The constructor takes precedence.struct S { int a, b; this(int bp, int ap) { a = ap; b = bp; } } writing S s = S(1, 2); what would it pick?The constructor.
Feb 13 2020
On Thursday, 13 February 2020 at 13:05:19 UTC, Steven Schveighoffer wrote:That page is *really* old. I think what Mike meant to say is that struct initializers and struct literals are both disabled once a constructor or opCall function is present. So in essence, the above struct S could NEVER be initialized except via constructor or with it's .init value. Having the named parameter DIP accepted means that now the constructor becomes possible to call like the initializer, assuming you gave bp and ap default values. -SteveIsn't that a bit restrictive? Wouldn't you like to have a constructor and sometimes parenthesis style initialization? With using parenthesis for everything there will be an ambiguity. In that case keeping () for constructor and {} for initialization would make it clear what the programmer wants. If the compiler cannot match a constructor it can go on and use initialization instead. Would this be too allowing and lead to that programmer errors are missed?
Feb 13 2020
On 2/13/20 10:49 AM, IGotD- wrote:On Thursday, 13 February 2020 at 13:05:19 UTC, Steven Schveighoffer wrote:You misunderstand. {} intialization today does not work when a constructor is defined: struct S { int a; this(int a) {this.a = a; } } void main() { S s = {a: 1}; } Error: struct S has constructors, cannot use { initializers }, use S( initializers ) instead So the only place this DIP would deprecate valid code is for structs without ctors. -SteveThat page is *really* old. I think what Mike meant to say is that struct initializers and struct literals are both disabled once a constructor or opCall function is present. So in essence, the above struct S could NEVER be initialized except via constructor or with it's .init value. Having the named parameter DIP accepted means that now the constructor becomes possible to call like the initializer, assuming you gave bp and ap default values.Isn't that a bit restrictive? Wouldn't you like to have a constructor and sometimes parenthesis style initialization? With using parenthesis for everything there will be an ambiguity. In that case keeping () for constructor and {} for initialization would make it clear what the programmer wants. If the compiler cannot match a constructor it can go on and use initialization instead. Would this be too allowing and lead to that programmer errors are missed?
Feb 13 2020
On 2/13/2020 7:49 AM, IGotD- wrote:Isn't that a bit restrictive?Yes, and it's on purpose. Note that this applies to C++ as well. If all the constructor does is supply its arguments to the fields, there's not point in providing one. If it does more than that, by using literals the user could bypass that, which would be a clear code smell if not an outright bug. Worse, it would be difficult to QA the code as the constructor call would look just like an initializer.
Feb 13 2020
On 2020-02-13 09:56:27 +0000, Walter Bright said:On 2/13/2020 1:47 AM, IGotD- wrote:I never understood (but expect some good reason to exists) why I can't write: S s(1,2); which IMO is the most compact and clear form. -- Robert M. Mnch http://www.saphirion.com smarter | better | fasterHowever, would S s = (1, 2); be allowed inferring the type?No. But you can write: auto s = S(1, 2);
Feb 13 2020
On Thursday, 13 February 2020 at 11:04:26 UTC, Robert M. Münch wrote:I never understood (but expect some good reason to exists) why I can't write: S s(1,2);It would only work in the context of a declaration, otherwise it's a CallExpression.
Feb 13 2020
On Thursday, 13 February 2020 at 11:04:26 UTC, Robert M. Münch wrote:On 2020-02-13 09:56:27 +0000, Walter Bright said:https://en.wikipedia.org/wiki/Most_vexing_parseOn 2/13/2020 1:47 AM, IGotD- wrote:I never understood (but expect some good reason to exists) why I can't write: S s(1,2); which IMO is the most compact and clear form.However, would S s = (1, 2); be allowed inferring the type?No. But you can write: auto s = S(1, 2);
Feb 13 2020
On 2/13/2020 4:54 AM, Atila Neves wrote:https://en.wikipedia.org/wiki/Most_vexing_parseYes. There's no reason to support such things. C++ has to because it made a mistake early on.
Feb 13 2020
On 2020-02-13 12:54:26 +0000, Atila Neves said:As I expected... thanks for the reference. -- Robert M. Mnch http://www.saphirion.com smarter | better | fasterI never understood (but expect some good reason to exists) why I can't write: S s(1,2); which IMO is the most compact and clear form.https://en.wikipedia.org/wiki/Most_vexing_parse
Feb 14 2020
On Thursday, 13 February 2020 at 09:47:13 UTC, IGotD- wrote:According to the DIP This will be deprecated. struct S { int a, b; } S s = { 1, 2 }; // Deprecated: use S(1, 2) instead So after this DIP we would write S s = S(1, 2); instead. However, would S s = (1, 2); be allowed inferring the type?This is allowed today: auto s = S(1, 2); This as well: alias args = AliasSeq!(1, 2); auto s = S(args); S s2 = S(args); If this was accepted: alias args = AliasSeq!(1, 2); S s = args; We could also write: S s = AliasSeq!(1, 2); And also, if Timon's proposal [1] is accepted, we would get built-in syntax for AliasSeq-es, so we would finally be able to write: S s = (1, 2); [1]: https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.mdWould there be case where this type of initialization would mask the constructor of a type or vice versa? Ex. struct S { int a, b; this(int bp, int ap) { a = ap; b = bp; } } writing S s = S(1, 2); what would it pick?A user-defined constructor prevents the generation of a compiler-synthesized one. In the code above, the result is `S(2, 1)`, i.e. `1` is assigned to `S.a` and `2` to `S.b`. This DIP won't change anything in this regard.
Feb 13 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:...Well first I'm not against this, but one thing that called my attention is that a while ago Manu proposed a DIP which was rejected (https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/rejected/DIP1016.md) In that case Walter/Andrei bashed that DIP for lack of rationale/description/cases and so on. I remember Andrei telling in this Forum, how a DIP should be written and he asked for a professional analysis and so on. Now this DIP is very thin (I think it couldn't fill a A4 paper) and I'm seeing this trending in every Walter's DIP. I mean the example shouldn't be set from they?
Feb 13 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.mdIf I understand correctly what this change means, I've already been using the 'new' way and didn't actually realize there was another way. So... I see no problems here.
Feb 13 2020
I'm against this change unless there's a good reason other than simplifying the language. The brace-style struct initializers allow for beautiful code. This comment summarizes it well: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320
Feb 13 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.mdI think this is heading in the right direction, however I see three issues: 1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`. This gets worse when a struct contains nested struct definitions, as Andre pointed out (here: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320). 2) It's actually part of 1, but I wanted to make it a separate issue because it's important. Not *all* usages of struct initializer can be replaced by the constructor syntax. For example: ``` --- definition.d module definition; struct Foo { private struct Bar { int a; int b; } Bar ber; } --- main.d module main; import definition; void main () { Foo f = { ber: { a: 42, b: 84 } }; } ``` To replace this usage, one has to use `typeof(Foo.ber)`. Even more verbose. 3) It's way, way too early to deprecate them. There is currently *no replacement available*. Some libraries try to keep compatibility for many versions (e.g. Vibe.d) and some projects tests with compilers that go way back (GDC-9 is the 2.076 FE and still used). I tried to deprecate the `body` keyword after `do` has been in for 10 releases, and had to revert it (https://github.com/dlang/dmd/pull/10763) because it still causes too much breakage. This fits your own definition of "shuffling things around to no benefit". I'm always happy to clean up the language, but it's a long and tedious process, and something that takes a lot of time in itself if we want to keep our users.
Feb 13 2020
On Friday, 14 February 2020 at 05:53:08 UTC, Mathias Lang wrote:On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:You have auto?This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.mdI think this is heading in the right direction, however I see three issues: 1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`.This gets worse when a struct contains nested struct definitions, as Andre pointed out (here: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320). 2) It's actually part of 1, but I wanted to make it a separate issue because it's important. Not *all* usages of struct initializer can be replaced by the constructor syntax. For example: ``` --- definition.d module definition; struct Foo { private struct Bar { int a; int b; } Bar ber; } --- main.d module main; import definition; void main () { Foo f = { ber: { a: 42, b: 84 } }; } ```This seems like a hole indeed. I wonder if it's worth considering though. My first thought is why is something that needs to be publicly constructed, not public? This looks fishy. There's a very valid use case when it comes to returning voldermort types that match a specific interface (i.e. ranges), but I've never seen anyone construct them. And over here we have a declaration of a type, why is only the name private?To replace this usage, one has to use `typeof(Foo.ber)`. Even more verbose. 3) It's way, way too early to deprecate them. There is currently *no replacement available*. Some libraries try to keep compatibility for many versions (e.g. Vibe.d) and some projects tests with compilers that go way back (GDC-9 is the 2.076 FE and still used).Yes, the deprecation should only happen after there's a replacement indeed (in general, not sure of that specific hole you showed above though).
Feb 13 2020
On Friday, 14 February 2020 at 07:09:05 UTC, aliak wrote:On Friday, 14 February 2020 at 05:53:08 UTC, Mathias Lang wrote:The real inconvenience shows up as you nest structure, which was in the second part of the quote. Consider `auto f = Foo(a: SomeType(b: SomeOtherType(x: 42)));`, it is not quite as readable as the struct literal alternative, and there's no way to use `auto` here, even though the expected type is known to the compiler and unambiguous. And I didn't even mention templates! Imagine if a struct is an aggregate of other templated struct, e.g. `struct Aggregated (T, TV = DefaultValue) { Foo!T f1; Bar!T f2; xvector!(T, TV) f3; }`. Have fun turning a struct literal for this into something that spells out the type. I usually keep my type names verbose but my fields name short, and use struct literal all over the place. It leads to expressive code that is easy to read and easy to write, and feels familiar to people used to read JSON or YAML.On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:You have auto?This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.mdI think this is heading in the right direction, however I see three issues: 1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`.[...] This seems like a hole indeed. I wonder if it's worth considering though. My first thought is why is something that needs to be publicly constructed, not public? This looks fishy. There's a very valid use case when it comes to returning voldermort types that match a specific interface (i.e. ranges), but I've never seen anyone construct them. And over here we have a declaration of a type, why is only the name private?I would strongly advise against trying to decide what is a "valid" use case. Just because someone approach a problem differently doesn't mean their solution is invalid.Yes, the deprecation should only happen after there's a replacement indeed (in general, not sure of that specific hole you showed above though).The point was that when we replace a feature, it should take years before the old version is deprecated if we want to be taken seriously as a language.
Feb 13 2020
On Friday, 14 February 2020 at 07:54:56 UTC, Mathias Lang wrote:I'm not sure I see where you're repeating types there. As for readability, I find Foo f = { ber: { a: 42, b: 84 } }; Less readable than: auto f = Foo( ber: Ber( a: 42, b: 84 ) ); (I've duplicated your spacing choices, but the extra type information is more useful to me at the call site).You have auto?The real inconvenience shows up as you nest structure, which was in the second part of the quote. Consider `auto f = Foo(a: SomeType(b: SomeOtherType(x: 42)));`, it is not quite as readable as the struct literal alternative, and there's no way to use `auto` here, even though the expected type is known to the compiler and unambiguous.And I didn't even mention templates! Imagine if a struct is an aggregate of other templated struct, e.g. `struct Aggregated (T, TV = DefaultValue) { Foo!T f1; Bar!T f2; xvector!(T, TV) f3; }`. Have fun turning a struct literal for this into something that spells out the type.That'd be not fun regardless of brace initializers or not.I would strongly advise against trying to decide what is a "valid" use case. Just because someone approach a problem differently doesn't mean their solution is invalid.If there's a bug in the type system it should be fixed. Not maintained. Not thinking about is would be the unadvisable part IMO.
Feb 14 2020
On Friday, 14 February 2020 at 13:47:38 UTC, aliak wrote:On Friday, 14 February 2020 at 07:54:56 UTC, Mathias Lang wrote:In this case I prefer the First one:I'm not sure I see where you're repeating types there. As for readability, I find Foo f = { ber: { a: 42, b: 84 } }; Less readable than: auto f = Foo( ber: Ber( a: 42, b: 84 ) ); (I've duplicated your spacing choices, but the extra type information is more useful to me at the call site).You have auto?The real inconvenience shows up as you nest structure, which was in the second part of the quote. Consider `auto f = Foo(a: SomeType(b: SomeOtherType(x: 42)));`, it is not quite as readable as the struct literal alternative, and there's no way to use `auto` here, even though the expected type is known to the compiler and unambiguous.Foo f = { ber: { a: 42, b: 84 } };Matheus.
Feb 14 2020
On Friday, 14 February 2020 at 07:54:56 UTC, Mathias Lang wrote:The real inconvenience shows up as you nest structure, which was in the second part of the quote. Consider `auto f = Foo(a: SomeType(b: SomeOtherType(x: 42)));`, it is not quite as readable as the struct literal alternative, and there's no way to use `auto` here, even though the expected type is known to the compiler and unambiguous. And I didn't even mention templates! Imagine if a struct is an aggregate of other templated struct, e.g. `struct Aggregated (T, TV = DefaultValue) { Foo!T f1; Bar!T f2; xvector!(T, TV) f3; }`. Have fun turning a struct literal for this into something that spells out the type. I usually keep my type names verbose but my fields name short, and use struct literal all over the place. It leads to expressive code that is easy to read and easy to write, and feels familiar to people used to read JSON or YAML.Perhaps declarative programming should be a first class feature, instead of using struct initializers to emulate it. The syntax could be similar to QML/DML: struct Type { string field1; string field2; NestedField field3; struct NestedField { int field1; } } struct AnotherType { int field1; } declare instance1 : Type { field1: "value"; field2: "value2"; field3.field1: 100; int field4: 5; AnotherType { field1: outer.field4 + 9; } } Lowers to something like: struct __instance1 { Type __type; alias type this; AnotherType __child_0; __constructor() { __type.field1 = "value"; __type.field2 = "value2"; __type.field3.field1 = 100; __child_0.field1 = __type.field4 + 9; } } __instance1 instance1;
Feb 14 2020
On 2/14/20 12:53 AM, Mathias Lang wrote:On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is probably less of a problem. If you need to initialize items via static construction with a private type, chances are the library gives you a mechanism to do that. However even when you have public access to the name, but the name is unwieldy (e.g. the templates in your followup message), makes this look like a bigger problem than the simple examples. Imagine a struct with a static array of structs. Currently you can do this: struct Vector2D { float x; float y; } struct Moves { Vector2D[4] items; } Moves awsd = {items: [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x:0, y:-1}]}; But with this DIP, the call now becomes: Moves awsd = Moves(items: [Vector2D(x: 1, y: 0), Vector2D(x: 0, y: 1), Vector2D(x: -1, y: 0), Vector2D(x:0, y:-1)]); Now, imagine Vector2D and Moves are templated on type! Would be horrendous. I can think of a solution though, just have a substitute for the real name of the type for struct initializers. In other words, this is not a function call, and does not have possible overloads. Something like: Foo f = Foo(ber: auto(a: 42, b: 84)); It's not as terse, but circumvents for the most part the issue of long names. You could even just keep the initializer syntax but with parentheses instead of braces: Foo f = Foo(ber: (a: 42, b: 84)); // only valid for struct initialization without a ctor. I think this would be unambiguous. But at that point, why are we even deprecating the current syntax? Indeed, I think instead of deprecation, we should first just provide the alternative, and see how it goes. I'm also not sure we even need to deprecate this feature. We aren't gaining anything syntax-wise, and it's not harmful for the compiler to support it as far as I can tell. -SteveThis is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451 763/DIPs/DIP1031.mdI think this is heading in the right direction, however I see three issues: 1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`. This gets worse when a struct contains nested struct definitions, as Andre pointed out (here: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320). 2) It's actually part of 1, but I wanted to make it a separate issue because it's important. Not *all* usages of struct initializer can be replaced by the constructor syntax. For example: ``` --- definition.d module definition; struct Foo { private struct Bar { int a; int b; } Bar ber; } --- main.d module main; import definition; void main () { Foo f = { ber: { a: 42, b: 84 } }; } ``` To replace this usage, one has to use `typeof(Foo.ber)`. Even more verbose.
Feb 14 2020
On Friday, 14 February 2020 at 14:46:43 UTC, Steven Schveighoffer wrote:On 2/14/20 12:53 AM, Mathias Lang wrote:I was thinking of this when you brought up that issue. https://github.com/dotnet/csharplang/issues/100 I.E. Moves awsd = Moves(items: [(x: 1, y: 0), (x: 0, y: 1), (x: -1, y: 0), (x:0, y:-1)]);On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is probably less of a problem. If you need to initialize items via static construction with a private type, chances are the library gives you a mechanism to do that. However even when you have public access to the name, but the name is unwieldy (e.g. the templates in your followup message), makes this look like a bigger problem than the simple examples. Imagine a struct with a static array of structs. Currently you can do this: struct Vector2D { float x; float y; } struct Moves { Vector2D[4] items; } Moves awsd = {items: [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x:0, y:-1}]}; But with this DIP, the call now becomes: Moves awsd = Moves(items: [Vector2D(x: 1, y: 0), Vector2D(x: 0, y: 1), Vector2D(x: -1, y: 0), Vector2D(x:0, y:-1)]); Now, imagine Vector2D and Moves are templated on type! Would be horrendous. I can think of a solution though, just have a substitute for the real name of the type for struct initializers. In other words, this is not a function call, and does not have possible overloads. Something like: Foo f = Foo(ber: auto(a: 42, b: 84)); It's not as terse, but circumvents for the most part the issue of long names. You could even just keep the initializer syntax but with parentheses instead of braces: Foo f = Foo(ber: (a: 42, b: 84)); // only valid for struct initialization without a ctor. I think this would be unambiguous. But at that point, why are we even deprecating the current syntax? Indeed, I think instead of deprecation, we should first just provide the alternative, and see how it goes. I'm also not sure we even need to deprecate this feature. We aren't gaining anything syntax-wise, and it's not harmful for the compiler to support it as far as I can tell. -SteveThis is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.mdI think this is heading in the right direction, however I see three issues: 1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`. This gets worse when a struct contains nested struct definitions, as Andre pointed out (here: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320). 2) It's actually part of 1, but I wanted to make it a separate issue because it's important. Not *all* usages of struct initializer can be replaced by the constructor syntax. For example: ``` --- definition.d module definition; struct Foo { private struct Bar { int a; int b; } Bar ber; } --- main.d module main; import definition; void main () { Foo f = { ber: { a: 42, b: 84 } }; } ``` To replace this usage, one has to use `typeof(Foo.ber)`. Even more verbose.
Feb 14 2020
On 2/14/20 9:46 AM, Steven Schveighoffer wrote:You could even just keep the initializer syntax but with parentheses instead of braces: Foo f = Foo(ber: (a: 42, b: 84)); // only valid for struct initialization without a ctor. I think this would be unambiguous. But at that point, why are we even deprecating the current syntax?Hm... a possible benefit that has not been discussed, brace-style initialization is only allowed during initialization, because there are no types involved in the initialization expression. But if we did the above, then the struct literal Foo(ber: (a: 42, b: 84)) would be allowed in any expression, since the types for each parameter are unambiguous. To recap: 1. We could make a struct literal syntax specifically for non-ctor structs that allows omission of types, since there are no overloads to worry about. 2. Such syntax would be valid wherever such a struct needs creation, including expressions. examples: struct S { int x; int y; } struct P // to demonstrate ambiguity { int y; int x; } struct NoCtor { S s; } struct Ctor { S s; this(S s) { this.s = s; } this(P s) { this.s = S(x: p.x, y: p.y); } } void foo(Ctor c); void foo(NoCtor nc); void main() { S s = S(x: 1, y: 2); // given by this DIP NoCtor nc = NoCtor(s: (x: 1, y: 2)); // also OK, not a function call NoCtor nc2 = NoCtor((1, 2)); // also OK, no names required once inside struct literal without ctor Ctor c = Ctor(s: (x: 1, y: 2)); // Error, would be ambiguous Ctor c = Ctor(s: S(x: 1, y: 2)); // Must supply full expression for ctor param foo(Ctor(s: P(x: 1, y: 2)); // OK foo(NoCtor(s: (x: 1, y: 2))); // OK, not a ctor function } Essentially POD types get an upgrade for their static initialization syntax to be allowed in expressions. -Steve
Feb 14 2020
On 2/14/20 11:39 AM, Steven Schveighoffer wrote:this(P s) { this.s = S(x: p.x, y: p.y); }ugh, didn't finish this edit. Should be: this(P s) { this.s = S(x: s.x, y: s.y); }
Feb 14 2020
On 2/14/2020 6:46 AM, Steven Schveighoffer wrote:Now, imagine Vector2D and Moves are templated on type! Would be horrendous.That's why D has alias declarations.
Feb 14 2020
On 2/14/20 4:49 PM, Walter Bright wrote:On 2/14/2020 6:46 AM, Steven Schveighoffer wrote:An alias declaration is a declaration. It needs its own line before the expression use. This is unwieldy as well, further squirreling away the definition from the usage, requiring more lookup time. Promoting "just use an alias" means someone just "quickly" adds an alias to make the thing short: alias X = Vector2D!double; ... // some many lines later auto awsd = Moves!double(items: [X(x: 1, y: 0), X(x: 0, y: 1), X(x: -1, y: 0), X(x:0, y:-1)]); Leaving the reader scratching his head at where X comes from after looking up the Moves layout and not seeing it there. Even with the alias, repeating the type over and over is really an exercise in rote frustration. Especially when the compiler already knows how to figure this out without help (it already does this correctly with struct initializer syntax today). -SteveNow, imagine Vector2D and Moves are templated on type! Would be horrendous.That's why D has alias declarations.
Feb 14 2020
On Friday, 14 February 2020 at 22:11:36 UTC, Steven Schveighoffer wrote:An alias declaration is a declaration. It needs its own line before the expression use. This is unwieldy as well, further squirreling away the definition from the usage, requiring more lookup time. Promoting "just use an alias" means someone just "quickly" adds an alias to make the thing short: alias X = Vector2D!double; ... // some many lines later auto awsd = Moves!double(items: [X(x: 1, y: 0), X(x: 0, y: 1), X(x: -1, y: 0), X(x:0, y:-1)]); Leaving the reader scratching his head at where X comes from after looking up the Moves layout and not seeing it there. Even with the alias, repeating the type over and over is really an exercise in rote frustration. Especially when the compiler already knows how to figure this out without help (it already does this correctly with struct initializer syntax today). -SteveYes, typing in the type name quickly gets old for these kinds of use cases. I previously asked if writing (x: 1, y: 0) would be enough and the compiler would infer the type itself. With your example not even auto(x: 1, y: 0) would be sufficient. As I see it in order for this DIP to pass and retain the usability just as before the compiler must infer the type just like with curly brackets.
Feb 14 2020
On 2/14/2020 2:11 PM, Steven Schveighoffer wrote:... // some many lines laterIt can be done inline with lambdas, like dmd itself does: https://github.com/dlang/dmd/blob/master/src/dmd/backend/oper.d#L387 and the lambdas can be arbitrarily complex. I wrote those bits to replace the optabgen.d program.
Feb 14 2020
On 2/14/20 6:44 PM, Walter Bright wrote:On 2/14/2020 2:11 PM, Steven Schveighoffer wrote:Not sure what this is supposed to mean. I hope not: auto moves = Moves!double(items: [(){return Vector2d!double(x: 1, y: 0); }(), ...]) -Steve... // some many lines laterIt can be done inline with lambdas, like dmd itself does: https://github.com/dlang/dmd/blob/master/src/dmd/backend/oper.d#L387 and the lambdas can be arbitrarily complex. I wrote those bits to replace the optabgen.d program.
Feb 15 2020
On 2/15/2020 6:23 AM, Steven Schveighoffer wrote:Not sure what this is supposed to mean.Generally, such things can get a lot clearer if you use better formatting rather than mushing it all into one line.
Feb 15 2020
On 2/14/2020 1:49 PM, Walter Bright wrote:On 2/14/2020 6:46 AM, Steven Schveighoffer wrote:You can also do: auto v(float a, float b) { return Vector2D(x: a, y: b); } and: Moves awsd = {items: [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x:0, y:-1}]}; becomes: auto awsd = Moves(items: [v(1,0), v(0,1), v(-1,0), v(0,-1)]); voila!Now, imagine Vector2D and Moves are templated on type! Would be horrendous.That's why D has alias declarations.
Feb 14 2020
On 2/14/20 6:10 PM, Walter Bright wrote:On 2/14/2020 1:49 PM, Walter Bright wrote:This is less attractive than the alias, because now I'm calling a function for all the items (and I still need an extra declaration somewhere). Not only that, but you modified the parameter names, so now it's a and b instead of x and y. And finally, you removed the documentation of what members the call is setting (the 'x' and 'y'). Still not as good IMO as the original call with brace style initialization, which needs no extra framework definitions, and no reason to search the code space for the "v" function to understand what it is doing. So far, this looks like a step backwards in code clarity, efficiency, and beauty. -SteveOn 2/14/2020 6:46 AM, Steven Schveighoffer wrote:You can also do: auto v(float a, float b) { return Vector2D(x: a, y: b); } and: Moves awsd = {items: [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x:0, y:-1}]}; becomes: auto awsd = Moves(items: [v(1,0), v(0,1), v(-1,0), v(0,-1)]); voila!Now, imagine Vector2D and Moves are templated on type! Would be horrendous.That's why D has alias declarations.
Feb 14 2020
The following code is from actual real world: VkPipelineViewportStateCreateInfo viewportStateInfo = { viewportCount : 1, pViewports : [ {0f, 0f, 1920f, 1080f, -1f, 1f} ], scissorCount : 1, pScissors : [ {{0, 0}, {1920, 1080}} ], }; If the brace-style struct initializers get deprecated this is what I have to write: auto viewportStateInfo = VkPipelineViewportStateCreateInfo( viewportCount : 1, pViewports : [ VkViewport(0f, 0f, 1920f, 1080f, -1f, 1f) ], scissorCount : 1, pScissors : [ VkRect2D(VkOffset2D(0, 0), VkExtent2D(1920, 1080))) ], ); The following is what it looks like if I use parameter names as well, and it's not hard to imagine having to write code like this if someone has complicated nested structures: auto viewportStateInfo = VkPipelineViewportStateCreateInfo( viewportCount : 1, pViewports : [ VkViewport(x:0f, y:0f, width:1920f, height:1080f, minDepth:-1f, maxDepth:1f) ], scissorCount : 1, pScissors : [ VkRect2D(offset: VkOffset2D(x:0, y:0), extent: VkExtent2D(width:1920, height:1080))) ], ); Absolutely not ideal. Doesn't scale. Too verbose. This feature should be improved instead of making it deprecated. I've never seen someone getting confused by brace-style syntax. I have also yet to discover any deal breaking issues about this feature, and it doesn't seem complicated to support **at all**. This would also break a good amount code and that is rather hard to automate by conventional text editing tools. (if only people cared about dfix huh...) Besides, I don't want my D code to look like java. I've had enough of that.
Feb 17 2020
On Friday, 14 February 2020 at 14:46:43 UTC, Steven Schveighoffer wrote:I can think of a solution though, just have a substitute for the real name of the type for struct initializers. In other words, this is not a function call, and does not have possible overloads. Something like: Foo f = Foo(ber: auto(a: 42, b: 84)); It's not as terse, but circumvents for the most part the issue of long names.I really like that. I just got a glimpse of Andre's issue [0] and deprecating brace initialization really is going to put a big blotch on that code of his. And the workaround suggested looks really bad :( Especially considering the file is long, the number of AWS types are HUGE and having aliases like alias A = AnAwsType alias B = AnotherAwsType . . . /// Really not scalable... [0] https://github.com/dlang/DIPs/pull/169#issuecomment-532830320
Feb 14 2020
On 2020-02-14 15:46, Steven Schveighoffer wrote:Foo f = Foo(ber: (a: 42, b: 84)); // only valid for struct(a: 42, b: 84) looks like a tuple with named elements to me. -- /Jacob Carlborg
Feb 15 2020
On Saturday, 15 February 2020 at 08:59:44 UTC, Jacob Carlborg wrote:On 2020-02-14 15:46, Steven Schveighoffer wrote:Exactly, a tuple-record hybrid. With Timon Gehr's tuple proposal + optionally named tuple elements + named parameters proposal, various forms of struct ctor invocation may become possible: Foo f = ((42, 84),) or Foo f = (ber: (a: 42, b: 84)) or auto f = Foo(ber: Bar(b: 84, a: 42)), etc.Foo f = Foo(ber: (a: 42, b: 84)); // only valid for struct(a: 42, b: 84) looks like a tuple with named elements to me.
Feb 15 2020
On 2/13/2020 9:53 PM, Mathias Lang wrote:1) The type name has to be repeated. So as mentioned, `Foo f = (42, 84);` would be more readable than `Foo f = Foo(42, 84);`.auto f = Foo(42, 84); // no repetitionThis gets worse when a struct contains nested struct definitions, as Andre pointed out (here: https://github.com/dlang/DIPs/pull/169#issuecomment-532830320).I replied to him there.--- definition.d module definition; struct Foo { private struct Bar { int a; int b; } Bar ber; } --- main.d module main; import definition; void main () { Foo f = { ber: { a: 42, b: 84 } }; } ``` To replace this usage, one has to use `typeof(Foo.ber)`. Even more verbose.For private structs like that, it's time to use an actual constructor. Frankly, allowing { } initializers for a private struct should be a bug, not a feature.3) It's way, way too early to deprecate them. There is currently *no replacement available*. Some libraries try to keep compatibility for many versions (e.g. Vibe.d) and some projects tests with compilers that go way back (GDC-9 is the 2.076 FE and still used).It's not a problem to stretch this out over time.This fits your own definition of "shuffling things around to no benefit".Significantly simplifying the language is not shuffling.
Feb 14 2020
On Friday, 14 February 2020 at 21:35:10 UTC, Walter Bright wrote: On 2/13/2020 9:53 PM, Mathias Lang wrote:Simplifying something isnt objectively better. Anyways, this is simplifying the language (by an insignificant margin) but greatly complicating large code that used this feature, that was being simplified as a result of the feature.This fits your own definition of "shuffling things around to no benefit".Significantly simplifying the language is not shuffling.
Feb 14 2020
On 2/14/2020 7:59 PM, jxel wrote:... greatly complicating ...I know that n.g. discussions have a tendency to defend to the death a single stone and forget the quarry, but come on.
Feb 14 2020
On Saturday, 15 February 2020 at 04:50:31 UTC, Walter Bright wrote:On 2/14/2020 7:59 PM, jxel wrote:If you have a large amount of code with nesting, yes. This is a big step backwards. The justification is flimsy and this will break code. There's bigger fish to fry that will have a more meaningful impact and won't break even more code.... greatly complicating ...I know that n.g. discussions have a tendency to defend to the death a single stone and forget the quarry, but come on.
Feb 14 2020
On 2/14/20 11:50 PM, Walter Bright wrote:On 2/14/2020 7:59 PM, jxel wrote:From the perspective of the user, the complications in the compiler or library are of zero significance. They care about what they have to write to get what they want, and how that code performs. In other words, they are not even in the quarry, but in the processing plant (or whatever you call the place the stones go after they are harvested). -Steve... greatly complicating ...I know that n.g. discussions have a tendency to defend to the death a single stone and forget the quarry, but come on.
Feb 15 2020
On 16/02/2020 3:39 AM, Steven Schveighoffer wrote:On 2/14/20 11:50 PM, Walter Bright wrote:Except when the compiler ICE's out, they certainly care then. Compiler errors are to be expected when you don't have a full time team working on a compilers internal. From Walter's perspective it makes sense to want to limit the surface area of potential new bugs when you don't have the support to back you up. You can talk about quarries and processing plants but either the customer gets the exact product they want in the time that they have paid for or they don't. If we genuinely cared about the user, we should be doing HCI studies and doing formal proving of language constructs. But we don't. We cut corners because we have no choice to do so as it is too costly. The best way to resolve this situation from what I've seen is to heed off as many different perspectives in the DIP and have the DIP author chime in to expand on the discussion as soon as reasonably possible. This is something Walter could improve on.On 2/14/2020 7:59 PM, jxel wrote:From the perspective of the user, the complications in the compiler or library are of zero significance. They care about what they have to write to get what they want, and how that code performs. In other words, they are not even in the quarry, but in the processing plant (or whatever you call the place the stones go after they are harvested). -Steve... greatly complicating ...I know that n.g. discussions have a tendency to defend to the death a single stone and forget the quarry, but come on.
Feb 15 2020
On 2/15/20 10:03 AM, rikki cattermole wrote:On 16/02/2020 3:39 AM, Steven Schveighoffer wrote:Sure, but it doesn't. brace-initializers have been in the language from the beginning and they are a proven feature.On 2/14/20 11:50 PM, Walter Bright wrote:Except when the compiler ICE's out, they certainly care then.On 2/14/2020 7:59 PM, jxel wrote:From the perspective of the user, the complications in the compiler or library are of zero significance. They care about what they have to write to get what they want, and how that code performs. In other words, they are not even in the quarry, but in the processing plant (or whatever you call the place the stones go after they are harvested).... greatly complicating ...I know that n.g. discussions have a tendency to defend to the death a single stone and forget the quarry, but come on.Compiler errors are to be expected when you don't have a full time team working on a compilers internal.In general having the compiler simpler means an easier-to-maintain compiler. But simplifying the language to remove already working and proven features isn't progress. Unless you give them a new feature that replaces it (which could happen, if we wanted it to).You can talk about quarries and processing plants but either the customer gets the exact product they want in the time that they have paid for or they don't.I think we are saying the same thing. The user only cares if it works, not how hard it was to implement. If it works as expected, and is bug free (it currently is), then to the user, removing it means losing the feature. It doesn't mean a less buggy compiler. It the brace initializers were riddled with bugs or design issues, then I can see a benefit for users. This isn't the case. Removing features has to have a better story than simplification of language. We could simplify foreach and for loops into just while loops. The language would be simpler and less surface area for mistakes. But the users would be not very happy about such a change. -Steve
Feb 15 2020
On Saturday, 15 February 2020 at 15:03:56 UTC, rikki cattermole wrote:From Walter's perspective it makes sense to want to limit the surface area of potential new bugs when you don't have the support to back you up.OK now let's not get too carried away. If that was even something Walter was considering he wouldn't be maintaining his own backend. I've come across a few code gen bugs, and they aren't fun to diagnose and fix especially with how poor quality the backend code is. Some 20 years of legacy ported from C over those years.
Feb 15 2020
On 2/15/2020 9:58 AM, jxel wrote:how poor quality the backend code is.Baloney. It's written in an older style, sure, but it's remarkably bug free considering how complex it is. The complexity is a result of the fiendishly complex x86 instructions set. The proof of its quality is it has successfully been extended from a purely 16 bit generator to 32 and extended again to 64 bit, and has been extended to support multiple ABIs and object file formats. The DFA optimizer has also proven to be fast and very robust.
Feb 15 2020
On Saturday, 15 February 2020 at 23:59:39 UTC, Walter Bright wrote:On 2/15/2020 9:58 AM, jxel wrote:No thank you, I don't eat baloney.how poor quality the backend code is.Baloney.It's written in an older style, sure, but it's remarkably bug free considering how complex it is. The complexity is a result of the fiendishly complex x86 instructions set.The x86 instruction set is complex, but it allows you to generate simpler assembly. The backend will never support ARM because its a simpler instruction set and architecture that leans heavily on the codegen/optimizer producing correct assembly.The proof of its quality is it has successfully been extended from a purely 16 bit generator to 32 and extended again to 64 bit, and has been extended to support multiple ABIs and object file formats.What you've just described is a symptom that leads to poor quality code. Some sort of Frankenstein that has to be mcgyvered into doing something it originally wasn't designed to do.
Feb 15 2020
On 2/15/2020 5:23 PM, jxel wrote:The backend will never support ARM because its a simpler instruction setThere actually was one for the ARM. It wasn't completed because the person writing it ran out of steam, not because he hit architectural dead ends. Besides, the idea that an architecture designed to support a kludgy instruction set can't support a regular one doesn't make much sense.What you've just described is a symptom that leads to poor quality code. Somesort of Frankenstein that has to be mcgyvered into doing something it originally wasn't designed to do. BTW, it was also extended to support the SIMD instruction set, which is architecturally fairly different. It was extended as well to support x87, which is architecturally rather unique. I'm amused that a hallmark of poor quality is being adaptable to diverse architectures. No other backend has ever been able to come close to its speed at the level of code quality it produces (it was originally designed to run on 16 bit floppy systems). But I'm open to suggestions for improvement of the quality. If you have something specific, PRs are welcome.
Feb 15 2020
On Sat, Feb 15, 2020 at 09:13:01PM -0800, Walter Bright via Digitalmars-d wrote: [...]I'm amused that a hallmark of poor quality is being adaptable to diverse architectures.Yeah, I think the original criticism here was a bit ridiculous. However:No other backend has ever been able to come close to its speed at the level of code quality it produces (it was originally designed to run on 16 bit floppy systems).What's the point of lightning fast generation of poor quality code? Okay, during development it's good to have fast turnaround times. But what when it's release time and I want to squeeze the last bit of juice from the generated code? Running dmd -O for this is, sorry to say, a disappointment. I've measured this against LDC and GDC, and they *consistently* produce code that outperforms dmd-generated code. A 20%/30% speedup is typical, sometimes with compute-heavy code it can be 40% faster than dmd generated code. I've been saying this for years, and even reported bugs about it. But so far, things have not changed very much. When runtime performance matters, I don't even consider dmd, I already know ldc/gdc will produce faster code. So sure, the dmd backend is the fastest of its kind that produces 20% slower code, but that's hardly something to boast about now, is it?But I'm open to suggestions for improvement of the quality. If you have something specific, PRs are welcome.Well this is part of the problem: because the code style is old and unfamiliar to most contemporary programmers, you're not going to find many people who would be able to contribute a PR. And those who can may not necessarily be willing to spend the time to do so. Chicken and egg problem. People *can* file bugs related to performance, though. I did. And I'm still waiting for results. T -- One reason that few people are aware there are programs running the internet is that they never crash in any significant way: the free software underlying the internet is reliable to the point of invisibility. -- Glyn Moody, from the article "Giving it all away"
Feb 15 2020
On 2/15/2020 10:27 PM, H. S. Teoh wrote:What's the point of lightning fast generation of poor quality code?The speed of the code generated was competitive with (and sometimes ahead of) the other compilers from 1985 to 2000 when I worked actively on it. It slowly fell behind after that as I was spending my time on the D front end. This is not evidence that the code quality of the back end is poor.Well this is part of the problem: because the code style is old and unfamiliar to most contemporary programmers, you're not going to find many people who would be able to contribute a PR. And those who can may not necessarily be willing to spend the time to do so. Chicken and egg problem.There are very, very few programmers out there who understand code generation issues well enough to improve things. It has nothing to do with the back end being old fashioned. The data structures in it are simple and straightforward. That said, some people have contributed some good work to the back end, but nothing fundamental.
Feb 16 2020
On Sun, Feb 16, 2020 at 12:18:30PM -0800, Walter Bright via Digitalmars-d wrote:On 2/15/2020 10:27 PM, H. S. Teoh wrote:Note that I did not say the code quality of the back end is poor. I said that the quality of the code *generated* by the back end is poor. And that's not in an absolute sense, since obviously it's still of the same quality as it was back in 2000, but it's poor in the relative sense, compared to the output of modern backends like GDC or LDC. The problem is that while the rest of the world has marched on since 2000, the DMD backend has remained stagnant. Effectively, therefore, it's regressing -- not in the absolute sense of course, but relative to the rest of the world that has since moved on. Which means that now it's a much harder sell to choose the DMD backend over, say, LDC or GDC's. As a user, I don't care how good the DMD backend is as long as its output is inferior compared to alternative backends; obviously I'm going to choose the backend that gives me better generated code, regardless of how either backend arrives at it. Maybe the GDC backend is garbage in terms of its own code quality (as an example -- I don't know the GDC backend code), but as long as the code it *generates* performs faster than the code DMD generates, users are going to choose it over DMD.What's the point of lightning fast generation of poor quality code?The speed of the code generated was competitive with (and sometimes ahead of) the other compilers from 1985 to 2000 when I worked actively on it. It slowly fell behind after that as I was spending my time on the D front end. This is not evidence that the code quality of the back end is poor.And that is precisely the problem. While GDC/LDC backends may or may not have the technical superiority over DMD's backend, what matters is that people are improving it over time, whereas the DMD backend has been staying stagnant. It doesn't matter what the reason is -- maybe programmers are not competent enough to work on the DMD backend, maybe there's some other reason, but what matters is that there are very few people actively improving the DMD backend, whereas there are large teams of people honing the GDC/LDC backends continually. Effectively, therefore, the DMD backend is regressing, not in the sense that it's actually *degrading*, but in the sense that it's lagging behind the other backends. No matter how technically superior the DMD code may be, and no matter how inferior the other backends may be, what the user is going to choose will be decided by what kind of code is generated, not by what kind of code the backend is running. The DMD backend can be superior all it wants, but if the code it generates is slower than the code produced by GDC or LDC, then there is really no reason for me to prefer DMD over GDC or LDC. Therein lies the rub. T -- Why are you blatanly misspelling "blatant"? -- Branden RobinsonWell this is part of the problem: because the code style is old and unfamiliar to most contemporary programmers, you're not going to find many people who would be able to contribute a PR. And those who can may not necessarily be willing to spend the time to do so. Chicken and egg problem.There are very, very few programmers out there who understand code generation issues well enough to improve things. It has nothing to do with the back end being old fashioned. The data structures in it are simple and straightforward. That said, some people have contributed some good work to the back end, but nothing fundamental.
Feb 16 2020
On Sunday, 16 February 2020 at 06:27:32 UTC, H. S. Teoh wrote:What's the point of lightning fast generation of poor quality code? Okay, during development it's good to have fast turnaround times. But what when it's release time and I want to squeeze the last bit of juice from the generated code?I don't know about you, but I spend like 99.9% of my time in the development phase and 0.1% in the final release build phase. In a lot of cases DMD produces code that's more than good enough, so I don't even both with LDC, but it really doesn't add anything to my development time to add a final call to LDC. If you could alias DMD -O to call LDC, you wouldn't notice the difference.
Feb 17 2020
On Sunday, 16 February 2020 at 05:13:01 UTC, Walter Bright wrote:PRs are welcome.They really aren't. Every time there's some sort of significant change of a pull request, you shut it down as 'reshuffling'. It's also not my job to cleanup. There's a perfectly fine D compiler with a quality backend known as LDC. The only pull request I'd make would be to merge LDC in.
Feb 16 2020
On 2/15/2020 6:39 AM, Steven Schveighoffer wrote:From the perspective of the user, the complications in the compiler or library are of zero significance.The complication is in the language. This affects the user: 1. the language is larger 2. user has to decide "should I do it the A way or the B way?" 3. documentation is longer 4. anyone writing a book/tutorial on D has to become proficient with it 5. introduces bugs (such as the one just noticed that the { } allows access to private fields) It is not at all zero.
Feb 15 2020
On Saturday, 15 February 2020 at 23:54:17 UTC, Walter Bright wrote:On 2/15/2020 6:39 AM, Steven Schveighoffer wrote:You could remove quite a few features, and prevent new ones for those reasons. Named parameters to start, especially with the current DIP that just introduces complexity for very little benefit and increases the burden on library authors to maintain compatibility. The new live attribute, that's going to add way more complexity. The "in" and "out" qualifiers aren't really needed, and kind of useless and redundant. The ?: operator, don't really need it, just use a normal if statement. The "const" qualifier could be removed and nothing of significance would be lost, no body uses it anyway. Interpolated strings as well, its just syntactic sugar. The in and out contracts, there's a bunch of bugs with those and really just having asserts in the body of the function provides basically the same functionality. I don't really see anyone using that feature. I'm sure I could go on with some more. Deprecate 'real', it should be a 128 bit float, no body uses 80 bit floats and just having it be the largest possible dp unit is just repeating c's mistakes. Anyways for sure now, there's probably more features that you could remove for the same rationale you are giving as this one. D has numerous issues with not following private. Its cause its not something that someone pays attention to. I forget if allMembers was updated to not all private access.or to allow it, either way its not just this one feature that breaks private.From the perspective of the user, the complications in the compiler or library are of zero significance.The complication is in the language. This affects the user: 1. the language is larger 2. user has to decide "should I do it the A way or the B way?" 3. documentation is longer 4. anyone writing a book/tutorial on D has to become proficient with it 5. introduces bugs (such as the one just noticed that the { } allows access to private fields) It is not at all zero.
Feb 15 2020
On 2/15/20 6:54 PM, Walter Bright wrote:On 2/15/2020 6:39 AM, Steven Schveighoffer wrote:All these points apply to for loops and foreach loops as well. All of these can be done with while loops. Yet, we don't want to remove them because they provide a good readable syntax for what is required in most cases. In my opinion, when you are adding features, you have a different bar to cross than when you are removing them. If adding, does the feature provide enough benefit syntactically over existing mechanisms to justify a language change. If removing, is there an alternate feature that can mimic it to a sufficient degree that we can remove it with a straightforward positive conversion? Look at octals and hex strings. Both of these were implemented via a library call that provided equivalent operation. The syntax sugar was gone, but octals were confusing and error prone in their current state (being more verbose there with an `octal!` was a benefit), and hex strings simply weren't worth an entire language feature for it when CTFE could do exactly the same thing with a single call (newCTFE will help here too). In this DIP, we are exploding the verbosity and repetitiveness to an uncomfortable degree, which frankly wasn't even necessary before. The brace syntax is beautifully minimal. If we can alleviate that concern, I think there would be no problem to remove this feature.From the perspective of the user, the complications in the compiler or library are of zero significance.The complication is in the language. This affects the user: 1. the language is larger 2. user has to decide "should I do it the A way or the B way?" 3. documentation is longer4. anyone writing a book/tutorial on D has to become proficient with itReally? You have to be proficient in D struct initializers to write a book? I'm pretty sure I have at least 2 D books without this in it. I actually don't ever use braced struct initializers. But the use cases that have been provided are pretty compelling, and your workarounds have not been. At least not enough to remove the syntax sugar provided without a comparable replacement.5. introduces bugs (such as the one just noticed that the { } allows access to private fields)Is that really a bug? Struct literals have this access as well. I'll also note that Mathias' example was not a private data member, but a private type (i.e. Voldemort type) with public members. His point was that everything being initialized was public, except the name. Which the new syntax requires whereas the old does not. .tupleof provides private access also. I think there are many libraries that probably depend on this, so you may want to deprecate that slowly. -Steve
Feb 15 2020
On 2/15/2020 7:20 PM, Steven Schveighoffer wrote:All these points apply to for loops and foreach loops as well. All of these can be done with while loops.It's the while loop that is redundant. foreach is key to writing generic code that would be impractical using for loops for.Yet, we don't want to remove them because they provide a good readable syntax for what is required in most cases.That's not really why. I can explain more if you like.In this DIP, we are exploding the verbosity and repetitiveness to an uncomfortable degree, which frankly wasn't even necessary before. The brace syntax is beautifully minimal.You said you don't use this syntax. I've used it since the beginning. I wouldn't miss it. Left unsaid in all this is the static initializer syntax can only be use for statics, and even then only for structs without a constructor. I've never heard a complaint about how terrible it was to use the function-style syntax, which is required for every other use. As for using Voldemort types in a static initializer, good luck contriving a use case for that. And if one manages to do it, there's still a usable workaround - typeof - which Mathias used.Ali's book certainly does (Section 47.3). Andrei's does not, it uses the function style syntax. --- BTW, if you want to present a DIP for anonymous struct literals, please do so.4. anyone writing a book/tutorial on D has to become proficient with itReally? You have to be proficient in D struct initializers to write a book? I'm pretty sure I have at least 2 D books without this in it.
Feb 15 2020
On Sunday, 16 February 2020 at 05:57:22 UTC, Walter Bright wrote:Left unsaid in all this is the static initializer syntax can only be use for statics, and even then only for structs without a constructor.It actually works for dynamic initialization too:The static initializer syntax can also be used to initialize non-static variables. The initializer need not be evaluable at compile time.Source: https://dlang.org/spec/struct.html#dynamic_struct_init
Feb 15 2020
On 2/15/2020 10:09 PM, Paul Backus wrote:On Sunday, 16 February 2020 at 05:57:22 UTC, Walter Bright wrote:Yes, you're right. My mistake.Left unsaid in all this is the static initializer syntax can only be use for statics, and even then only for structs without a constructor.It actually works for dynamic initialization too:The static initializer syntax can also be used to initialize non-static variables. The initializer need not be evaluable at compile time.Source: https://dlang.org/spec/struct.html#dynamic_struct_init
Feb 17 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers": https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.md Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits... in other words, business as usual. However, if you have any specific feedback for how to improve the the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post. Just be sure to read and understand the Reviewer Guidelines before posting there: https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md The review period will end at 11:59 PM ET on February 27, or when I make a post declaring it complete. Discussion in this thread may continue beyond that point. At the end of Round 1, if further review is deemed necessary, the DIP will be scheduled for another round of Community Review. Otherwise, it will be queued for the Final Review and Formal Assessment. Please stay on topic here. I will delete posts that are completely off topic.:( I really like them and would prefer to have them do more. So currently I can write this: struct Q { int b; string c; } struct S { int a; Q q; } S s = { a: 3, q: { b: 5, c: "hello" } } and that's great. But what I'd really love to be able to do would be this: S foo() { return { a: 3, q: { b: 5, c: "hello" } }; } and Tuple!(int, "a", int, "b") bar() { return { x: 3, y: 7 }; } and even auto bar() { return { x: 3, y: 7 }; } static assert(is(typeof(bar()) == Tuple!(int, "x", int, "y"))); Although probably not lowering to the phobos std.typecons.Tuple for obvious reasons. Anonymous structures are great.
Feb 15 2020
On Saturday, 15 February 2020 at 21:59:26 UTC, John Colvin wrote:On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:I know this statement is completely unconstuctive but 😍[...]:( I really like them and would prefer to have them do more. So currently I can write this: struct Q { int b; string c; } struct S { int a; Q q; } S s = { a: 3, q: { b: 5, c: "hello" } } and that's great. But what I'd really love to be able to do would be this: S foo() { return { a: 3, q: { b: 5, c: "hello" } }; } and Tuple!(int, "a", int, "b") bar() { return { x: 3, y: 7 }; } and even auto bar() { return { x: 3, y: 7 }; } static assert(is(typeof(bar()) == Tuple!(int, "x", int, "y"))); Although probably not lowering to the phobos std.typecons.Tuple for obvious reasons. Anonymous structures are great.
Feb 15 2020
On Saturday, 15 February 2020 at 21:59:26 UTC, John Colvin wrote::( I really like them and would prefer to have them do more. [...] But what I'd really love to be able to do would be this: S foo() { return { a: 3, q: { b: 5, c: "hello" } }; } and [...]This (and the rest of the post) 100%. The only thing that ever annoyed me about struct literals is that they don't work everywhere.
Feb 16 2020
On Sunday, 16 February 2020 at 15:24:26 UTC, Mathias Lang wrote:[..] The only thing that ever annoyed me about struct literals is that they don't work everywhere.I completely agree. I have several developers on my team with mostly JavaScript/TypeScript background, and it would be quite difficult to introduce D to them without the relatable (and also people for coming from C) struct literal syntax. These days is quite rare to find a JS/TS project that doesn't make a heavy use of this feature: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment https://javascript.info/destructuring-assignment If accepting the named parameters proposal meant that we could simply replace braces with parentheses, I'd onboard with DIP1031, but not before. (Of course that would involve a semantic change, as currently the brace literal syntax works only for initializing structs without constructors and named parameters are meant to invoke either the user defined constructor or the default synthesized one.)
Feb 17 2020
On Thursday, 13 February 2020 at 07:29:00 UTC, Mike Parker wrote:This is the feedback thread for the first round of Community Review for DIP 1031, "Deprecate Brace-Style Struct Initializers":Effectlively this DIP proposes simplifying the compiler - not so much the language itself - primarily because this feature is used seldomly and provides little value. But there are several problem which undermine this rationale. I would argue that this feature is one of the simpler features of for beginners to learn. You have a struct, enumerate it's field with appropriate values and get an initialized instance. This has compelling use cases (which Andre already presented) and were the alternatives are much more verbose. This is in conflict with one of D's core strengths, writing expressive and clean code. This leads to the question why this feature is rarely used. The current discussion mentions them being type system holes (because they circumvent constructors) [1] and their restriction to variable initializers [2]. I think we should address these issues to increase the usability of the current syntax instead of simply deprecating it. Suggestions: [1] Deprecate (and soon disallow) brace-style initializers for non-PODs [2] Allow brace-style initializers wherever a corresponding struct rvalue is allowed (and can be resolved unambiguously)
Feb 16 2020
Would removing support for brace-style struct initializers significantly simplify or speed up some portion of DMD?
Feb 16 2020
On 2/16/2020 11:38 PM, Nathan S. wrote:Would removing support for brace-style struct initializers significantly simplify or speed up some portion of DMD?No.
Feb 17 2020