www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - struct initializer

reply Dom DiSc <dominikus scherkl.de> writes:
```d
struct S { int a; int b; }

S s = { 5, 2 }; // works fine

S fun() { return { 5, 2 }; } // doesn't work :-(

S fun2() { S s = { 5, 2 }; return s; } // works but is ugly

struct S2 { int a; int b; this(int c, int d) { a=c; b=d; } }

S2 fun3() { return S2( 5, 2 ); } // works but requires explicit 
constructor
```

Is there a reason why the short form is not possible?
It's clearly an initialization of a new instance of a struct, and 
the requested type is unambigous (the return type of the 
function).
Nov 29 2023
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 29 November 2023 at 16:38:36 UTC, Dom DiSc wrote:
 ```d
 struct S2 { int a; int b; this(int c, int d) { a=c; b=d; } }

 S2 fun3() { return S2( 5, 2 ); } // works but requires explicit 
 constructor
 ```
You can use this syntax without an explicit constructor: struct S3 { int a; int b; } S3 fun() { return S3(5, 2); } The language spec calls this a [struct literal][1]. If you're using a new enough compiler, it even supports named arguments: S3 fun2() { return S3(b: 2, a: 5); } [1]: https://dlang.org/spec/struct.html#struct-literal
Nov 29 2023
next sibling parent reply Antonio <antoniocabreraperez gmail.com> writes:
On Wednesday, 29 November 2023 at 16:48:09 UTC, Paul Backus wrote:
 ... it even supports named arguments:
- Witch version of DMD supports named arguments? Is it an experimental compiler option?
Nov 29 2023
parent Paul Backus <snarwin gmail.com> writes:
On Wednesday, 29 November 2023 at 17:23:04 UTC, Antonio wrote:
 On Wednesday, 29 November 2023 at 16:48:09 UTC, Paul Backus 
 wrote:
 ... it even supports named arguments:
- Witch version of DMD supports named arguments? Is it an experimental compiler option?
I don't know what the earliest version is that supports it, but I know the example I posted works in 2.105. It doesn't require any compiler options. Named arguments are still a work in progress, and there are some situations where they aren't available (for example, I don't think they work for templates yet). With struct literals, though, you shouldn't have any problems using them.
Nov 29 2023
prev sibling next sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
On Wednesday, 29 November 2023 at 16:48:09 UTC, Paul Backus wrote:
 You can use this syntax without an explicit constructor:

     struct S3 { int a; int b; }

     S3 fun() { return S3(5, 2); }

 The language spec calls this a struct literal
Ok, so we have ```d struct S { int a; int b; } S s = S(5, 3); // works s = S(6, 2); // works S fun() { return S(5, 2); } // works int fun2(S s2); fun2(S(4,4)); // works ``` but ```d struct S { int a; int b; } S s = { 5, 3 }; // works s = { 6, 2 }; // doesn't work S fun() { return { 5, 2 }; } // doesn't work int fun2(S s2); fun2(S(4,4)); // doesn't work ``` So, why supporting the (somewhat strange looking) version with curly backets at all? It only works in one special place, so is simply overhead to remember. Again a superfluous way to do the same - but only under specific circumstances. I think a syntax should work either always or never.
Nov 29 2023
next sibling parent Dom DiSc <dominikus scherkl.de> writes:
Sorry, I meant
 ```d
 fun2({4, 4}); // doesn't work
 ```
Nov 29 2023
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Thursday, 30 November 2023 at 07:21:29 UTC, Dom DiSc wrote:
 So, why supporting the (somewhat strange looking) version with 
 curly backets at all?
 It only works in one special place, so is simply overhead to 
 remember.
 Again a superfluous way to do the same - but only under 
 specific circumstances.

 I think a syntax should work either always or never.
The syntax was inherited from C. The 'special place' is called initialization, and it's special because the target type of the initializer is known in advance, while normal expression assignments are analyzed bottom up. Since there is no `typeof({10, 10})`, struct initializers don't work as expressions. C99 added Compound literals `(S){.a = 10, .b = 20}`, and with named arguments you can do the same in D: `S(a: 10, b:20)`, and since the type name is included, they do work as standalone expressions. Walter tried to deprecate the old struct initializer syntax: https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1031.md But it got some resistance, since {} initializers still have an advantage when you want to define an array of structs, and don't want to repeat the (potentially long) struct name for every entry. Also note that even when {} is removed, there are still other special cases with initialization, for example with arrays: ```D void main() { short[] a = [3: 10]; // ok a = [3: 10]; // cannot implicitly convert expression `[3:10]` of type `int[int]` to `short[]` } ```
Nov 30 2023
parent Dom DiSc <dominikus scherkl.de> writes:
On Thursday, 30 November 2023 at 12:15:04 UTC, Dennis wrote:
 The syntax was inherited from C. The 'special place' is called 
 initialization, and it's special because the target type of the 
 initializer is known in advance
This is no different from `S fun(){ return { 5, 2 }; }` It creates a new instance of a struct, and the type is known in advance (it's the return type). So it's not an expression. But this place of initialization is not allowed. Therefor I think calling `S s = { 5, 2 };` 'special' is justified.
Dec 01 2023
prev sibling parent kdevel <kdevel vogtner.de> writes:
On Wednesday, 29 November 2023 at 16:48:09 UTC, Paul Backus wrote:
 [...]
 If you're using a new enough compiler, it even supports named
 arguments:

     S3 fun2() { return S3(b: 2, a: 5); }
Indeed. Seems to be in dmd since 2.103.0 (2.102.2 didn't support this syntax). Alas, the Change Log [1] remain silent about it. ``` commit 42609ae98e0f72a8d2154da50865bc5182c4b6b3 Author: Dennis <d[...] Date: Tue Jan 17 13:08:30 2023 +0100 * Add named argument parsing [...] ``` The named parameters are not restricted to struct constructors: ```d import std.stdio; auto delta (int from, int to) { return to - from; } void main () { writeln (delta (to: 8, from: 1)); } ``` ``` $ dmd structinit.d $ ./structinit 7 ``` [1] https://dlang.org/changelog/2.103.0.html
Dec 01 2023
prev sibling next sibling parent reply zjh <fqbqrr 163.com> writes:
On Wednesday, 29 November 2023 at 16:38:36 UTC, Dom DiSc wrote:

```d
 struct S { int a; int b; }
 S2 fun3() { return S2( 5, 2 ); }
``` Here,`S2( 5, 2 );` violeit `DRY` principle.
Nov 30 2023
parent reply Dom DiSc <dominikus scherkl.de> writes:
On Thursday, 30 November 2023 at 14:10:35 UTC, zjh wrote:
 On Wednesday, 29 November 2023 at 16:38:36 UTC, Dom DiSc wrote:

 ```d
 struct S { int a; int b; }
 S2 fun3() { return S2( 5, 2 ); }
``` Here,`S2( 5, 2 );` violeit `DRY` principle.
Yes. I think if we have the brackets form, it should be allowed here: ```d S Fun(){ return { 5, 2 }; } ``` This IS an initialization and the type is known. Requiring the repetition of the type is also here annoying. So it is not a syntax reserved for initialization, but only for initialization with equals operator. I think this is inconsequent. Either allow it for all initializations, or get rid of it, like DIP 1031 suggested.
Dec 01 2023
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Friday, 1 December 2023 at 13:02:06 UTC, Dom DiSc wrote:
 Either allow it for all initializations, or get rid of it, like 
 DIP 1031 suggested.
I thought the decision actually was made to just get rid of it.
Dec 01 2023
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Friday, 1 December 2023 at 13:02:06 UTC, Dom DiSc wrote:
 ```d
 S Fun(){ return { 5, 2 }; }
 ```

 This IS an initialization and the type is known. Requiring the 
 repetition of the type is also here annoying.
Right. The `{}` initialization method in C++ is very useful,I like it very much.
Dec 01 2023
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 1 December 2023 at 13:02:06 UTC, Dom DiSc wrote:
 ```d
 S Fun(){ return { 5, 2 }; }
 ```

 This IS an initialization and the type is known. Requiring the 
 repetition of the type is also here annoying.
Technically you don't *have* to repeat the type. You can write the return type as `auto`: ```d auto fun() { return S(5, 2); } ``` Or you can use `typeof(return)`: ```d SomeReallyLongReturnType fun() { return typeof(return)(5, 2); } ```
Dec 01 2023
parent Salih Dincer <salihdb hotmail.com> writes:
Hi All,

I feel lonely, just as those who come from C++ find it strange, 
because I think it makes it difficult to read code.

On Friday, 1 December 2023 at 14:53:16 UTC, Paul Backus wrote:
 Technically you don't *have* to repeat the type. You can write 
 the return type as `auto`:

 ```d
 auto fun() { return S(5, 2); }
 ```

 Or you can use `typeof(return)`:

 ```d
 SomeReallyLongReturnType fun()
 {
     return typeof(return)(5, 2);
 }
 ```
Paul's example is very readable and short so it's nice. Moreover, when there are named parameters in D, what is the need for them. While there is so much convenience in D, getting stuck on a very simple option... You decide: ```d struct Point { int x, y; auto opBinary(string op : "-")(Point that) => Point(this.x - that.x, this.y - that.y); auto opBinary(string op : "+")(Point that) => Point(this.x + that.x, this.y + that.y); auto opBinary(string op : "*")(Point that) => Point(this.x * that.x, this.y * that.y); // Moreover, it was possible to do this trio // at once with mixin... } void main() { auto upperRightCorner = Point(y:768); Point x = { 10, 268 }; import std.stdio : dout = writeln; dout(upperRightCorner - x); dots(a: upperRightCorner, b: x).dout; } alias dots = differenceOfTwoSquares; auto differenceOfTwoSquares(Point a, Point b) => (a - b)*(a + b); /* * dmd -run "namedParameters.d" * Point(-10, 500) * Point(-100, 518000) */ ``` SDB 79
Dec 01 2023
prev sibling parent bomat <Tempest_spam gmx.de> writes:
I completely agree with the OP, and I want to illustrate this by 
another example which I find quite bizarre:

```
struct S { int a; int b; }
S[] s_list = new S[0];

// this works
S s = { a:1, b:2 };
s_list ~= s;

// this does not
s_list ~= { a:1, b:2 };
```

I'm a C++ programmer in my day job and the very first instinct 
I'd have is to replace the first version by the second to reduce 
verbosity and eliminate an unnecessary copy.

However, for some reason the compiler is not able to deduce the 
type in the second case, so I'm out of luck.

I'm glad to hear that, with a compiler update, I will at least be 
able to do
```
s_list ~= S( a:1, b:2 );
```
instead of
```
s_list ~= S( 1, 2 );
```
but it still seems very inconsistent.
Dec 01 2023