February 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
February 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); }
February 14, 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 repetition


>      This 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.


February 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.
February 14, 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
February 14, 2020
On 2/14/20 4:49 PM, Walter Bright wrote:
> 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.

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).

-Steve
February 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).
>
> -Steve

Yes, 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.

February 14, 2020
On 2/14/2020 1:49 PM, Walter Bright wrote:
> 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.

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!
February 14, 2020
On 2/14/20 6:10 PM, Walter Bright wrote:
> On 2/14/2020 1:49 PM, Walter Bright wrote:
>> 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.
> 
> 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!

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.

-Steve
February 14, 2020
On 2/14/2020 2:11 PM, Steven Schveighoffer wrote:
> ... // some many lines later

It 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.