www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Initialization of struct containing anonymous union

reply Carl Sturtivant <sturtivant gmail.com> writes:
   struct mess
   {
     union
     {
         int i;
         string s;
     }
     double x;
   }

How do I cleanly initialize this, assuming it's i that I want to 
give an overt value to?

The docs say "If there are anonymous unions in the struct, only 
the first member of the anonymous union can be initialized with a 
struct literal, and all subsequent non-overlapping fields are 
default initialized". This is not helpful.
https://dlang.org/spec/struct.html#struct-literal

The above is a toy example distilled from a real problem. The 
struct comes from a C library and is very long and contains 
several anonymous unions. The D declaration of the struct was 
made by someone else who made the library available to D.

I printed out such a struct returned by a call to the library, 
and wanted to create my own from scratch. But it seems that I 
can't just copy what writeln printed and edit it into an 
initialization analogous to

   mess m = { 99, 3.14 };

with the above, because I just get the analog of

Error: overlapping initialization for field i and s
Error: cannot implicitly convert expression (3.14) of type double 
to string

and the alternative more like what is printed by writeln,

   auto m = mess(99, 3.14);

produces a similar error message.

So it seems I am forced to assign explicitly to each member of 
the struct, an ugly process.

What is a nice way to solve this problem?
Aug 14 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/14/17 9:49 AM, Carl Sturtivant wrote:
    struct mess
    {
      union
      {
          int i;
          string s;
      }
      double x;
    }
 
 How do I cleanly initialize this, assuming it's i that I want to give an 
 overt value to?
 
 The docs say "If there are anonymous unions in the struct, only the 
 first member of the anonymous union can be initialized with a struct 
 literal, and all subsequent non-overlapping fields are default 
 initialized". This is not helpful.
 https://dlang.org/spec/struct.html#struct-literal
 
 The above is a toy example distilled from a real problem. The struct 
 comes from a C library and is very long and contains several anonymous 
 unions. The D declaration of the struct was made by someone else who 
 made the library available to D.
 
 I printed out such a struct returned by a call to the library, and 
 wanted to create my own from scratch. But it seems that I can't just 
 copy what writeln printed and edit it into an initialization analogous to
 
    mess m = { 99, 3.14 };
 
 with the above, because I just get the analog of
 
 Error: overlapping initialization for field i and s
 Error: cannot implicitly convert expression (3.14) of type double to string
I think what the docs mean is that as soon as an anonymous union is present, you can't initialize anything further than the first union field.
 and the alternative more like what is printed by writeln,
 
    auto m = mess(99, 3.14);
 
 produces a similar error message.
 
 So it seems I am forced to assign explicitly to each member of the 
 struct, an ugly process.
 
 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; } -Steve
Aug 14 2017
parent reply Carl Sturtivant <sturtivant gmail.com> writes:
On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer 
wrote:
 I think what the docs mean is that as soon as an anonymous 
 union is present, you can't initialize anything further than 
 the first union field.
I understood that, hence my remark that "this is not helpful".
 So it seems I am forced to assign explicitly to each member of 
 the struct, an ugly process.
 
 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; }
As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution. I can print out such a struct using writeln, but can find no way to use that text cleaned up in source code to create such a struct. Is D completely deficient here?
Aug 14 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/14/17 10:36 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer wrote:
 I think what the docs mean is that as soon as an anonymous union is 
 present, you can't initialize anything further than the first union 
 field.
I understood that, hence my remark that "this is not helpful".
OK. I thought you meant that the documentation is not helpful enough to understand what it means.
 
 So it seems I am forced to assign explicitly to each member of the 
 struct, an ugly process.

 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; }
As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution.
Sorry, I thought you meant to assign the fields manually outside an initializer function.
 I can print out such a struct using writeln, but can 
 find no way to use that text cleaned up in source code to create such a 
 struct. Is D completely deficient here?
Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14}; Seems to work for me. I believe you could generate a constructor given the introspection of the fields themselves. Probably would be messy though. -Steve
Aug 14 2017
parent reply Carl Sturtivant <sturtivant gmail.com> writes:
On Monday, 14 August 2017 at 14:49:57 UTC, Steven Schveighoffer 
wrote:
 On 8/14/17 10:36 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:24:40 UTC, Steven 
 Schveighoffer wrote:
 I think what the docs mean is that as soon as an anonymous 
 union is present, you can't initialize anything further than 
 the first union field.
I understood that, hence my remark that "this is not helpful".
OK. I thought you meant that the documentation is not helpful enough to understand what it means.
 
 So it seems I am forced to assign explicitly to each member 
 of the struct, an ugly process.

 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; }
As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution.
Sorry, I thought you meant to assign the fields manually outside an initializer function.
 I can print out such a struct using writeln, but can find no 
 way to use that text cleaned up in source code to create such 
 a struct. Is D completely deficient here?
Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14};
I could do that, but again it would involve finding the 50 or 100 names and writing text that looks quite like the text of an assignment except using colon instead of equals. So just as long and ugly.
 I believe you could generate a constructor given the 
 introspection of the fields themselves. Probably would be messy 
 though.
Probably worth investigating, though not handy when quickly writing a short one-off tool. Was hoping D would have a better way.
Aug 14 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/14/17 10:57 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:49:57 UTC, Steven Schveighoffer wrote:
 On 8/14/17 10:36 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer wrote:
 I think what the docs mean is that as soon as an anonymous union is 
 present, you can't initialize anything further than the first union 
 field.
I understood that, hence my remark that "this is not helpful".
OK. I thought you meant that the documentation is not helpful enough to understand what it means.
 So it seems I am forced to assign explicitly to each member of the 
 struct, an ugly process.

 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; }
As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution.
Sorry, I thought you meant to assign the fields manually outside an initializer function.
 I can print out such a struct using writeln, but can find no way to 
 use that text cleaned up in source code to create such a struct. Is D 
 completely deficient here?
Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14};
I could do that, but again it would involve finding the 50 or 100 names and writing text that looks quite like the text of an assignment except using colon instead of equals. So just as long and ugly.
Well, you only have to initialize the ones that aren't defaulted. So in some use cases, this is hugely beneficial. But it seems in your case, you want to intialize everything explicitly (but only one member from each union). Tried this, also works. Looks like you just have to name items after the unions (i.e. when you are skipping members). Ugly, but passable: struct mess { union { int i; string s; } double x; int z; } mess s = {99, x: 3.14, 5}; -Steve
Aug 14 2017
parent Carl Sturtivant <sturtivant gmail.com> writes:
On Monday, 14 August 2017 at 15:11:35 UTC, Steven Schveighoffer 
wrote:
 On 8/14/17 10:57 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:49:57 UTC, Steven 
 Schveighoffer wrote:
 On 8/14/17 10:36 AM, Carl Sturtivant wrote:
 On Monday, 14 August 2017 at 14:24:40 UTC, Steven 
 Schveighoffer wrote:
 I think what the docs mean is that as soon as an anonymous 
 union is present, you can't initialize anything further 
 than the first union field.
I understood that, hence my remark that "this is not helpful".
OK. I thought you meant that the documentation is not helpful enough to understand what it means.
 So it seems I am forced to assign explicitly to each 
 member of the struct, an ugly process.

 What is a nice way to solve this problem?
I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; }
As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution.
Sorry, I thought you meant to assign the fields manually outside an initializer function.
 I can print out such a struct using writeln, but can find no 
 way to use that text cleaned up in source code to create 
 such a struct. Is D completely deficient here?
Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14};
I could do that, but again it would involve finding the 50 or 100 names and writing text that looks quite like the text of an assignment except using colon instead of equals. So just as long and ugly.
Well, you only have to initialize the ones that aren't defaulted. So in some use cases, this is hugely beneficial. But it seems in your case, you want to intialize everything explicitly (but only one member from each union). Tried this, also works. Looks like you just have to name items after the unions (i.e. when you are skipping members). Ugly, but passable: struct mess { union { int i; string s; } double x; int z; } mess s = {99, x: 3.14, 5}; -Steve
! Agreed!
Aug 14 2017