www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Union redux

reply "deadalnix" <deadalnix gmail.com> writes:
After discussion at DConf, it ends up that union have some lack 
of specification, and some nonsensical behavior right now. Here 
are some points discussed and possible solutions :

1/ .init for unions is not defined. I propose to define it as the 
.init of the first field + padding with 0s if the union is larger 
than its first member. It seems to be what is generated right now.

2/ Default constructor takes one argument per union's field and 
assign them all one over the other. This does not make any sense 
and need to be changed. Proposed solutions :
  a. Define one constructor for the first field.
  b. Define N constructors, one per field.
  c. Do not define constructors.

My preference goes for b, then a, then c, in that order.

3/ union and  safe is currently undefined. I proposed to make 
everything involving unions  system, and we will figure it out 
from there. At the very least, all union with indirections and 
fields having a posblit/destructor ust be  system.

4/ tupleof for unions generate a tuple will all field of the 
union. It does not make much sense, and it is unclear if tupleof 
can make sense at all on a union. Let's not have tupleof on union 
at all.

5/ union currently disallow members with postblit and/or 
destructor . It seems that this was needed in C++ as per Andrei's 
comments. It seems to me that, because of manual memory 
management, C++ would have a lot more struct with copy 
constructor and/or destructor than in D, so I'm not sure if this 
require change in spec. Andrei, can you give more details on the 
C++ situation here ?

6/ struct with anonymous union in them define one parameter per 
union field in the default constructor. This should probably lead 
to the same solution as 2/

7/ struct with anonymous union in them have one entry per union 
field in their tupleof. All the union field should be present as 
one entry in the tupleof, with a compiler generated union type.

8/ unions and structs are mangled the same way (or so it seems). 
Bug or feature ?

9/ union alignement is not specified. union align should be least 
common multiple of union's fields.

10/ union that capture a closure are undefined. I think that 
right now, they just add the context pointer at the same address 
as other fields, which is nonsensical. Proposal :
  a. Add the context at an address that do not overlap with other 
fields.
  b. Do not allow union to capture a context.

Union can have member method and they could use captured info to 
know how to process the union in an opaque (voldemort) way. I see 
no reason to forbid it, and adding an exception for union create 
extra special casing (from a user standpoint) which is 
undesirable. My preference goes to a.
Jun 01 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 12:00 PM, deadalnix wrote:
 1/ .init for unions is not defined. I propose to define it as the .init
 of the first field + padding with 0s if the union is larger than its
 first member. It seems to be what is generated right now.
Fine.
 2/ Default constructor takes one argument per union's field and assign
 them all one over the other. This does not make any sense and need to be
 changed. Proposed solutions :
   a. Define one constructor for the first field.
   b. Define N constructors, one per field.
   c. Do not define constructors.

 My preference goes for b, then a, then c, in that order.
Do not define constructors. They ostensibly imply commitment to remembering to call the appropriate destructor. A union can only be default constructed (with its init value as described) and has no destructor.
 3/ union and  safe is currently undefined. I proposed to make everything
 involving unions  system, and we will figure it out from there. At the
 very least, all union with indirections and fields having a
 posblit/destructor ust be  system.
A good first step. Let's.
 4/ tupleof for unions generate a tuple will all field of the union. It
 does not make much sense, and it is unclear if tupleof can make sense at
 all on a union. Let's not have tupleof on union at all.
tupleof must generate a tuple recognizable by introspection engines. I therefore thing tupleof with all members is the only approach that doesn't lose information. Introspection engines can check is(X == union) prior to interpreting tupleof.
 5/ union currently disallow members with postblit and/or destructor . It
 seems that this was needed in C++ as per Andrei's comments. It seems to
 me that, because of manual memory management, C++ would have a lot more
 struct with copy constructor and/or destructor than in D, so I'm not
 sure if this require change in spec. Andrei, can you give more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
 6/ struct with anonymous union in them define one parameter per union
 field in the default constructor. This should probably lead to the same
 solution as 2/
Structs can have auto-defined ctors only up to the union member.
 7/ struct with anonymous union in them have one entry per union field in
 their tupleof. All the union field should be present as one entry in the
 tupleof, with a compiler generated union type.
Again the litmus test here is enabling introspection. Structs with anonymous union members should have one member called e.g. __anonymous__ in their tupleof, and in turn introspecting that member should list its tuple.
 8/ unions and structs are mangled the same way (or so it seems). Bug or
 feature ?
Not sure. Walter?
 9/ union alignement is not specified. union align should be least common
 multiple of union's fields.
Yes. Since they're all powers of 2, taking the max is the same thing. BTW, to my surprise on OSX real.alignof is 16, but the alignof a union containing a real is 8. I think that's a bug. Please verify and file.
 10/ union that capture a closure are undefined. I think that right now,
 they just add the context pointer at the same address as other fields,
 which is nonsensical. Proposal :
   a. Add the context at an address that do not overlap with other fields.
   b. Do not allow union to capture a context.
No context please. We may add it later. I'd say check the existing semantics, file bug reports, and make PRs for a section on unions in the language reference that links to the issues wherever the actual behavior is not in sync with the spec. Andrei
Jun 01 2015
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/1/2015 12:43 PM, Andrei Alexandrescu wrote:
 On 6/1/15 12:00 PM, deadalnix wrote:
 1/ .init for unions is not defined. I propose to define it as the .init
 of the first field + padding with 0s if the union is larger than its
 first member. It seems to be what is generated right now.
Fine.
"Fine" as in "yes" :-) For non-native speakers, the use of "fine" is often confusing. "Fine" in American english means "you're wrong, but I won't argue the point." It does not signify endorsement.
 2/ Default constructor takes one argument per union's field and assign
 them all one over the other. This does not make any sense and need to be
 changed. Proposed solutions :
   a. Define one constructor for the first field.
   b. Define N constructors, one per field.
   c. Do not define constructors.

 My preference goes for b, then a, then c, in that order.
Do not define constructors. They ostensibly imply commitment to remembering to call the appropriate destructor. A union can only be default constructed (with its init value as described) and has no destructor.
Yes. Option (c). (We can always relax this later, but undoing (a) or (b) may be impossible.)
 3/ union and  safe is currently undefined. I proposed to make everything
 involving unions  system, and we will figure it out from there.
No.
 At the
 very least, all union with indirections and fields having a
 posblit/destructor ust be  system.
Yes.
 4/ tupleof for unions generate a tuple will all field of the union. It
 does not make much sense, and it is unclear if tupleof can make sense at
 all on a union. Let's not have tupleof on union at all.
tupleof must generate a tuple recognizable by introspection engines. I therefore thing tupleof with all members is the only approach that doesn't lose information. Introspection engines can check is(X == union) prior to interpreting tupleof.
Yes.
 5/ union currently disallow members with postblit and/or destructor . It
 seems that this was needed in C++ as per Andrei's comments. It seems to
 me that, because of manual memory management, C++ would have a lot more
 struct with copy constructor and/or destructor than in D, so I'm not
 sure if this require change in spec. Andrei, can you give more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
I defer to Andrei's expertise here.
 6/ struct with anonymous union in them define one parameter per union
 field in the default constructor. This should probably lead to the same
 solution as 2/
Structs can have auto-defined ctors only up to the union member.
Yes.
 7/ struct with anonymous union in them have one entry per union field in
 their tupleof. All the union field should be present as one entry in the
 tupleof, with a compiler generated union type.
Again the litmus test here is enabling introspection. Structs with anonymous union members should have one member called e.g. __anonymous__ in their tupleof, and in turn introspecting that member should list its tuple.
Sounds good.
 8/ unions and structs are mangled the same way (or so it seems). Bug or
 feature ?
Not sure. Walter?
I think it's fine.
 9/ union alignement is not specified. union align should be least common
 multiple of union's fields.
Yes. Since they're all powers of 2, taking the max is the same thing. BTW, to my surprise on OSX real.alignof is 16, but the alignof a union containing a real is 8. I think that's a bug. Please verify and file.
Union alignment must be the largest alignment of any of its fields. The same as for structs.
 10/ union that capture a closure are undefined. I think that right now,
 they just add the context pointer at the same address as other fields,
 which is nonsensical. Proposal :
   a. Add the context at an address that do not overlap with other fields.
   b. Do not allow union to capture a context.
No context please. We may add it later.
Yes. Option (b) - issue an error if it is attempted.
 I'd say check the existing semantics, file bug reports, and make PRs for a
 section on unions in the language reference that links to the issues wherever
 the actual behavior is not in sync with the spec.
Yes.
Jun 01 2015
next sibling parent reply "CraigDillabaugh" <craig.dillabaugh gmail.com> writes:
On Monday, 1 June 2015 at 21:02:30 UTC, Walter Bright wrote:
 On 6/1/2015 12:43 PM, Andrei Alexandrescu wrote:
 On 6/1/15 12:00 PM, deadalnix wrote:
 1/ .init for unions is not defined. I propose to define it as 
 the .init
 of the first field + padding with 0s if the union is larger 
 than its
 first member. It seems to be what is generated right now.
Fine.
"Fine" as in "yes" :-) For non-native speakers, the use of "fine" is often confusing. "Fine" in American english means "you're wrong, but I won't argue the point." It does not signify endorsement.
Maybe this explains why my wife was upset with me when she asked how she looked and I said "Fine".
 8/ unions and structs are mangled the same way (or so it 
 seems). Bug or
 feature ?
Not sure. Walter?
I think it's fine.
So are you saying you think don't think they are mangled the same way, but that you don't want to bother arguing. Craig
Jun 01 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/1/2015 2:17 PM, CraigDillabaugh wrote:
 Not sure. Walter?
I think it's fine.
So are you saying you think don't think they are mangled the same way, but that you don't want to bother arguing.
Hah, I should have said that "fine" has the meaning reversed when it is used as a single word sentence. "Seems fine", or "That's fine" indicate approval.
Jun 01 2015
parent reply "wobbles" <grogan.colin gmail.com> writes:
On Monday, 1 June 2015 at 22:45:55 UTC, Walter Bright wrote:
 On 6/1/2015 2:17 PM, CraigDillabaugh wrote:
 Not sure. Walter?
I think it's fine.
So are you saying you think don't think they are mangled the same way, but that you don't want to bother arguing.
Hah, I should have said that "fine" has the meaning reversed when it is used as a single word sentence. "Seems fine", or "That's fine" indicate approval.
English is a wonderful language :)
Jun 02 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/2/2015 1:34 AM, wobbles wrote:
 On Monday, 1 June 2015 at 22:45:55 UTC, Walter Bright wrote:
 On 6/1/2015 2:17 PM, CraigDillabaugh wrote:
 Not sure. Walter?
I think it's fine.
So are you saying you think don't think they are mangled the same way, but that you don't want to bother arguing.
Hah, I should have said that "fine" has the meaning reversed when it is used as a single word sentence. "Seems fine", or "That's fine" indicate approval.
English is a wonderful language :)
Reminds me of a friend who said he enjoyed programming the Z80. I said the Z80 was exceptionally complicated. He replied that's what he liked about it - he could make that processor sing like nobody else. Anybody could program a simple CPU. (He wrote software for arcade games back in the 70's.)
Jun 02 2015
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/1/15 5:02 PM, Walter Bright wrote:
 On 6/1/2015 12:43 PM, Andrei Alexandrescu wrote:
 On 6/1/15 12:00 PM, deadalnix wrote:
 1/ .init for unions is not defined. I propose to define it as the .init
 of the first field + padding with 0s if the union is larger than its
 first member. It seems to be what is generated right now.
Fine.
"Fine" as in "yes" :-) For non-native speakers, the use of "fine" is often confusing. "Fine" in American english means "you're wrong, but I won't argue the point." It does not signify endorsement.
Yes and no :) It all depends on the context and emotion. There is so little emotion in posts, and having one-word sentences doesn't help. Reading "Fine." in context of all of Andrei's other answers, I took it to mean "yeah, that's fine" -- i.e. "I agree"
 5/ union currently disallow members with postblit and/or destructor . It
 seems that this was needed in C++ as per Andrei's comments. It seems to
 me that, because of manual memory management, C++ would have a lot more
 struct with copy constructor and/or destructor than in D, so I'm not
 sure if this require change in spec. Andrei, can you give more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
I defer to Andrei's expertise here.
I would make it clear here what you mean. I can't tell what "the rule" is (there may be 2 rules, or 1, but I can't tell), and whether Andrei agrees we should do it or not. -Steve
Jun 01 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 2:22 PM, Steven Schveighoffer wrote:
 I would make it clear here what you mean. I can't tell what "the rule"
 is (there may be 2 rules, or 1, but I can't tell), and whether Andrei
 agrees we should do it or not.
Unions should accept all types, including those with disabled or elaborated constructors/postblits/dtors. Essentially a union is appropriate storage for any type mentioned in its members, whilst leaving it to its user to write and read the needed values. -- Andrei
Jun 01 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/1/15 5:36 PM, Andrei Alexandrescu wrote:
 On 6/1/15 2:22 PM, Steven Schveighoffer wrote:
 I would make it clear here what you mean. I can't tell what "the rule"
 is (there may be 2 rules, or 1, but I can't tell), and whether Andrei
 agrees we should do it or not.
Unions should accept all types, including those with disabled or elaborated constructors/postblits/dtors. Essentially a union is appropriate storage for any type mentioned in its members, whilst leaving it to its user to write and read the needed values. -- Andrei
So what happens on destruction? What about postblit? This was the piece I'm not understanding. For D, requiring that a struct can be constructed statically is a win here. -Steve
Jun 01 2015
next sibling parent Brad Roberts via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 6/1/15 2:40 PM, Steven Schveighoffer via Digitalmars-d wrote:
 On 6/1/15 5:36 PM, Andrei Alexandrescu wrote:
 On 6/1/15 2:22 PM, Steven Schveighoffer wrote:
 I would make it clear here what you mean. I can't tell what "the rule"
 is (there may be 2 rules, or 1, but I can't tell), and whether Andrei
 agrees we should do it or not.
Unions should accept all types, including those with disabled or elaborated constructors/postblits/dtors. Essentially a union is appropriate storage for any type mentioned in its members, whilst leaving it to its user to write and read the needed values. -- Andrei
So what happens on destruction? What about postblit? This was the piece I'm not understanding. For D, requiring that a struct can be constructed statically is a win here. -Steve
I think the basic thinking is that these two should be semantically identical: struct(T) { T t; } and struct(T) { union { T } U; U t; } Having extra members inside the union certainly make the topic a little more complex, certainly, but the above should be a good base to start from.
Jun 01 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 2:40 PM, Steven Schveighoffer wrote:
 So what happens on destruction?
Nothing happens.
 What about postblit?
Nothing happens. Andrei
Jun 01 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/02/2015 01:55 AM, Andrei Alexandrescu wrote:
 On 6/1/15 2:40 PM, Steven Schveighoffer wrote:
 So what happens on destruction?
Nothing happens.
 What about postblit?
Nothing happens. Andrei
Is there an official way to invoke them manually?
Jun 02 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 3:43 AM, Timon Gehr wrote:
 On 06/02/2015 01:55 AM, Andrei Alexandrescu wrote:
 On 6/1/15 2:40 PM, Steven Schveighoffer wrote:
 So what happens on destruction?
Nothing happens.
 What about postblit?
Nothing happens. Andrei
Is there an official way to invoke them manually?
destroy calls the dtor. Just copying out the appropriate member invokes postblit on the target. Also emplace is good for construction. -- Andrei
Jun 02 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/02/2015 09:48 PM, Andrei Alexandrescu wrote:
 On 6/2/15 3:43 AM, Timon Gehr wrote:
 On 06/02/2015 01:55 AM, Andrei Alexandrescu wrote:
 On 6/1/15 2:40 PM, Steven Schveighoffer wrote:
 So what happens on destruction?
Nothing happens.
 What about postblit?
Nothing happens. Andrei
Is there an official way to invoke them manually?
destroy calls the dtor. Just copying out the appropriate member invokes postblit on the target. Also emplace is good for construction. -- Andrei
OK. What about copying in instead of out?
Jun 02 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
Jun 02 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/2/15 6:14 PM, Andrei Alexandrescu wrote:
 On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
My concern is if you copy the enclosing type. This means you have already copied the bits, and the postblit of the enclosing type is responsible for calling the postblit of the valid union member (as defined by the semantics of the type). How does it do that? -Steve
Jun 02 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 3:42 PM, Steven Schveighoffer wrote:
 On 6/2/15 6:14 PM, Andrei Alexandrescu wrote:
 On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
My concern is if you copy the enclosing type. This means you have already copied the bits, and the postblit of the enclosing type is responsible for calling the postblit of the valid union member (as defined by the semantics of the type). How does it do that?
Copying unions as a whole won't do any miracles. Just memcpy. -- Andrei
Jun 02 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/03/2015 01:07 AM, Andrei Alexandrescu wrote:
 On 6/2/15 3:42 PM, Steven Schveighoffer wrote:
 On 6/2/15 6:14 PM, Andrei Alexandrescu wrote:
 On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
My concern is if you copy the enclosing type. This means you have already copied the bits, and the postblit of the enclosing type is responsible for calling the postblit of the valid union member (as defined by the semantics of the type). How does it do that?
Copying unions as a whole won't do any miracles. Just memcpy. -- Andrei
Copy is memcpy & postblit. If the bit-copy has already been done (e.g. execution is inside a postblit) emplace(&f,f) seems wasteful.
Jun 02 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 4:14 PM, Timon Gehr wrote:
 On 06/03/2015 01:07 AM, Andrei Alexandrescu wrote:
 On 6/2/15 3:42 PM, Steven Schveighoffer wrote:
 On 6/2/15 6:14 PM, Andrei Alexandrescu wrote:
 On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
My concern is if you copy the enclosing type. This means you have already copied the bits, and the postblit of the enclosing type is responsible for calling the postblit of the valid union member (as defined by the semantics of the type). How does it do that?
Copying unions as a whole won't do any miracles. Just memcpy. -- Andrei
Copy is memcpy & postblit. If the bit-copy has already been done (e.g. execution is inside a postblit) emplace(&f,f) seems wasteful.
Oh, I only now understood the question. Yes, it's possible to only call postblit if defined: static if (hasElaborateCopyConstructor!T) tvar.__postblit(); Andrei
Jun 02 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/03/2015 02:51 AM, Andrei Alexandrescu wrote:
 On 6/2/15 4:14 PM, Timon Gehr wrote:
 On 06/03/2015 01:07 AM, Andrei Alexandrescu wrote:
 On 6/2/15 3:42 PM, Steven Schveighoffer wrote:
 On 6/2/15 6:14 PM, Andrei Alexandrescu wrote:
 On 6/2/15 2:57 PM, Timon Gehr wrote:
 OK. What about copying in instead of out?
If the appropriate type has already been constructed, assignment suffices. Otherwise, emplace(&target, source) is needed. -- Andrei
My concern is if you copy the enclosing type. This means you have already copied the bits, and the postblit of the enclosing type is responsible for calling the postblit of the valid union member (as defined by the semantics of the type). How does it do that?
Copying unions as a whole won't do any miracles. Just memcpy. -- Andrei
Copy is memcpy & postblit. If the bit-copy has already been done (e.g. execution is inside a postblit) emplace(&f,f) seems wasteful.
Oh, I only now understood the question. Yes, it's possible to only call postblit if defined: static if (hasElaborateCopyConstructor!T) tvar.__postblit(); Andrei
Indeed, but I think this facility is undocumented. Maybe it should be exposed via the standard library?
Jun 02 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/2/15 8:53 PM, Timon Gehr wrote:
 On 06/03/2015 02:51 AM, Andrei Alexandrescu wrote:
 Oh, I only now understood the question. Yes, it's possible to only call
 postblit if defined:

 static if (hasElaborateCopyConstructor!T)
      tvar.__postblit();
The sad part is, I knew this :(
 Indeed, but I think this facility is undocumented. Maybe it should be
 exposed via the standard library?
I don't see the need. It's simply the name of the compiled member. I think it should be documented, however. -Steve
Jun 02 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 5:53 PM, Timon Gehr wrote:
 Indeed, but I think this facility is undocumented. Maybe it should be
 exposed via the standard library?
A good idea, please bugzilla so we don't forget. -- Andrei
Jun 02 2015
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/03/2015 03:47 AM, Andrei Alexandrescu wrote:
 On 6/2/15 5:53 PM, Timon Gehr wrote:
 Indeed, but I think this facility is undocumented. Maybe it should be
 exposed via the standard library?
A good idea, please bugzilla so we don't forget. -- Andrei
https://issues.dlang.org/show_bug.cgi?id=14646
Jun 03 2015
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 2:02 PM, Walter Bright wrote:
 For non-native speakers, the use of "fine" is often confusing. "Fine" in
 American english means "you're wrong, but I won't argue the point." It
 does not signify endorsement.
Thanks for the lesson. Indeed I did mean it as "yes". -- Andrei
Jun 01 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 2:02 PM, Walter Bright wrote:
 3/ union and  safe is currently undefined. I proposed to make everything
 involving unions  system, and we will figure it out from there.
No.
What should we do here then? -- Andrei
Jun 01 2015
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, 1 June 2015 at 21:32:32 UTC, Andrei Alexandrescu wrote:
 On 6/1/15 2:02 PM, Walter Bright wrote:
 3/ union and  safe is currently undefined. I proposed to 
 make everything
 involving unions  system, and we will figure it out from 
 there.
No.
What should we do here then? -- Andrei
The fact that we essentially decided that everything was safe until proven otherwise - i.e. used a blacklist for safety rather than a whitelist - has already proven to be a problem in that we keep missing stuff, and changing the rules later (like we will need to fix safety issues) will break existing code. It minimum, if we're not sure that something is safe, we need to make it system. As it stands, we've definitely dropped the ball on this. https://issues.dlang.org/show_bug.cgi?id=8838 is one example of that. - Jonathan M Davis
Jun 01 2015
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/1/2015 2:32 PM, Andrei Alexandrescu wrote:
 On 6/1/15 2:02 PM, Walter Bright wrote:
 3/ union and  safe is currently undefined. I proposed to make everything
 involving unions  system, and we will figure it out from there.
No.
What should we do here then? -- Andrei
There's nothing unsafe about: union { char c; int i; }
Jun 01 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 3:44 PM, Walter Bright wrote:
 On 6/1/2015 2:32 PM, Andrei Alexandrescu wrote:
 On 6/1/15 2:02 PM, Walter Bright wrote:
 3/ union and  safe is currently undefined. I proposed to make
 everything
 involving unions  system, and we will figure it out from there.
No.
What should we do here then? -- Andrei
There's nothing unsafe about: union { char c; int i; }
Sounds good, no indirection => safety is in good shape. -- Andrei
Jun 01 2015
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 1 June 2015 at 19:43:33 UTC, Andrei Alexandrescu wrote:
 Do not define constructors. They ostensibly imply commitment to 
 remembering to call the appropriate destructor. A union can 
 only be default constructed (with its init value as described) 
 and has no destructor.
This is implied in C++ because of manual memory management. I don't think it is in D.
 5/ union currently disallow members with postblit and/or 
 destructor . It
 seems that this was needed in C++ as per Andrei's comments. It 
 seems to
 me that, because of manual memory management, C++ would have a 
 lot more
 struct with copy constructor and/or destructor than in D, so 
 I'm not
 sure if this require change in spec. Andrei, can you give more 
 details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
Without knowing the rationale in C++, it is difficult to assert that this is also valid in D. You seems to be knowledgeable of the subject, so surely you can enlight us on that one.
 7/ struct with anonymous union in them have one entry per 
 union field in
 their tupleof. All the union field should be present as one 
 entry in the
 tupleof, with a compiler generated union type.
Again the litmus test here is enabling introspection. Structs with anonymous union members should have one member called e.g. __anonymous__ in their tupleof, and in turn introspecting that member should list its tuple.
Compiler generated tuples are auto flattening in D. That would not work unless the entry in the struct tuple is an (compiler generated) union.
 9/ union alignement is not specified. union align should be 
 least common
 multiple of union's fields.
Yes. Since they're all powers of 2, taking the max is the same thing. BTW, to my surprise on OSX real.alignof is 16, but the alignof a union containing a real is 8. I think that's a bug. Please verify and file.
Indeed, max is the same thing, but because of plateform specific characteristics. I don't think we should rely on them unless we need to (implementation can still use max).
Jun 01 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 3:43 PM, deadalnix wrote:
 On Monday, 1 June 2015 at 19:43:33 UTC, Andrei Alexandrescu wrote:
 Do not define constructors. They ostensibly imply commitment to
 remembering to call the appropriate destructor. A union can only be
 default constructed (with its init value as described) and has no
 destructor.
This is implied in C++ because of manual memory management. I don't think it is in D.
It is because destructors exist in both languages.
 5/ union currently disallow members with postblit and/or destructor . It
 seems that this was needed in C++ as per Andrei's comments. It seems to
 me that, because of manual memory management, C++ would have a lot more
 struct with copy constructor and/or destructor than in D, so I'm not
 sure if this require change in spec. Andrei, can you give more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
Without knowing the rationale in C++, it is difficult to assert that this is also valid in D. You seems to be knowledgeable of the subject, so surely you can enlight us on that one.
I intentionally gave enough information to allow easy further research. http://goo.gl/19Nol5 lists N2412 and N2248 as top hits, their motivation sections are relevant.
 7/ struct with anonymous union in them have one entry per union field in
 their tupleof. All the union field should be present as one entry in the
 tupleof, with a compiler generated union type.
Again the litmus test here is enabling introspection. Structs with anonymous union members should have one member called e.g. __anonymous__ in their tupleof, and in turn introspecting that member should list its tuple.
Compiler generated tuples are auto flattening in D. That would not work unless the entry in the struct tuple is an (compiler generated) union.
So it seems like generating an __anonymous__ name is the way to go. Andrei
Jun 01 2015
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 2 June 2015 at 00:11:09 UTC, Andrei Alexandrescu 
wrote:
 On 6/1/15 3:43 PM, deadalnix wrote:
 On Monday, 1 June 2015 at 19:43:33 UTC, Andrei Alexandrescu 
 wrote:
 Do not define constructors. They ostensibly imply commitment 
 to
 remembering to call the appropriate destructor. A union can 
 only be
 default constructed (with its init value as described) and 
 has no
 destructor.
This is implied in C++ because of manual memory management. I don't think it is in D.
It is because destructors exist in both languages.
It is common in D to have a struct with a constructor and no destructor.
 5/ union currently disallow members with postblit and/or 
 destructor . It
 seems that this was needed in C++ as per Andrei's comments. 
 It seems to
 me that, because of manual memory management, C++ would have 
 a lot more
 struct with copy constructor and/or destructor than in D, so 
 I'm not
 sure if this require change in spec. Andrei, can you give 
 more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
Without knowing the rationale in C++, it is difficult to assert that this is also valid in D. You seems to be knowledgeable of the subject, so surely you can enlight us on that one.
I intentionally gave enough information to allow easy further research. http://goo.gl/19Nol5 lists N2412 and N2248 as top hits, their motivation sections are relevant.
The abstract of the 2 above mentioned link only discuss the *constructor* case. It was never question of struct with constructor not being able to be in union. You attitude is only weakening your point.
Jun 01 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 7:18 PM, deadalnix wrote:
 On Tuesday, 2 June 2015 at 00:11:09 UTC, Andrei Alexandrescu wrote:
 On 6/1/15 3:43 PM, deadalnix wrote:
 On Monday, 1 June 2015 at 19:43:33 UTC, Andrei Alexandrescu wrote:
 Do not define constructors. They ostensibly imply commitment to
 remembering to call the appropriate destructor. A union can only be
 default constructed (with its init value as described) and has no
 destructor.
This is implied in C++ because of manual memory management. I don't think it is in D.
It is because destructors exist in both languages.
It is common in D to have a struct with a constructor and no destructor.
Probably there's a misunderstanding then. I'm saying the right way to go is unions have no destructors at all.
 5/ union currently disallow members with postblit and/or destructor
 . It
 seems that this was needed in C++ as per Andrei's comments. It
 seems to
 me that, because of manual memory management, C++ would have a lot
 more
 struct with copy constructor and/or destructor than in D, so I'm not
 sure if this require change in spec. Andrei, can you give more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
Without knowing the rationale in C++, it is difficult to assert that this is also valid in D. You seems to be knowledgeable of the subject, so surely you can enlight us on that one.
I intentionally gave enough information to allow easy further research. http://goo.gl/19Nol5 lists N2412 and N2248 as top hits, their motivation sections are relevant.
The abstract of the 2 above mentioned link only discuss the *constructor* case. It was never question of struct with constructor not being able to be in union.
Then again sorry I am misunderstanding something. I'm saying the right way to go is unions accept all types.
 You attitude is only weakening your point.
I'm not making a point. There is no debate. You said you want to work on unions, that would be great. But this is a cut and dried area. There's no room for creativity here. If you want to be creative and design new programming language facilities, do something else. For unions do what needs be done. Thanks, Andrei
Jun 01 2015
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 2 June 2015 at 02:32:55 UTC, Andrei Alexandrescu 
wrote:
 On 6/1/15 7:18 PM, deadalnix wrote:
 On Tuesday, 2 June 2015 at 00:11:09 UTC, Andrei Alexandrescu 
 wrote:
 On 6/1/15 3:43 PM, deadalnix wrote:
 On Monday, 1 June 2015 at 19:43:33 UTC, Andrei Alexandrescu 
 wrote:
 Do not define constructors. They ostensibly imply 
 commitment to
 remembering to call the appropriate destructor. A union can 
 only be
 default constructed (with its init value as described) and 
 has no
 destructor.
This is implied in C++ because of manual memory management. I don't think it is in D.
It is because destructors exist in both languages.
It is common in D to have a struct with a constructor and no destructor.
Probably there's a misunderstanding then. I'm saying the right way to go is unions have no destructors at all.
No, I asked you what is the rationale used to get types with postblit/destructor in unions (right now, the spec says no). I asked about the rationale for introduction of element with destructor/copy constructor in C++, but it turns out that the link provided also include constructor, and, in fact, only explore the constructor case in the rationale. It is important to consider why C++ did something to know if it makes sense to import it in D. I remind you that this is a change that you propose to the current state of affairs, meaning the burden of proof in on you.
 5/ union currently disallow members with postblit and/or 
 destructor
 . It
 seems that this was needed in C++ as per Andrei's 
 comments. It
 seems to
 me that, because of manual memory management, C++ would 
 have a lot
 more
 struct with copy constructor and/or destructor than in D, 
 so I'm not
 sure if this require change in spec. Andrei, can you give 
 more details
 on the C++ situation here ?
That rule has hurt C++ everywhere, and the community credits Lois Goldthwaite for pushing the current rule, which allows types with cdtors in unions. Let's go the same way, unions are all but useless otherwise.
Without knowing the rationale in C++, it is difficult to assert that this is also valid in D. You seems to be knowledgeable of the subject, so surely you can enlight us on that one.
I intentionally gave enough information to allow easy further research. http://goo.gl/19Nol5 lists N2412 and N2248 as top hits, their motivation sections are relevant.
The abstract of the 2 above mentioned link only discuss the *constructor* case. It was never question of struct with constructor not being able to be in union.
Then again sorry I am misunderstanding something. I'm saying the right way to go is unions accept all types.
You are saying this. Many on that thread said otherwise. I personally have no strong opinion one way or another. That is why I'm asking about what makes you think element with postblit/destructor needs to be accepted in unions, in order to have all elements I needs to have an informed opinion. Right now I'm not getting any of it, and instead I'm getting confrontation. That is not productive.
 You attitude is only weakening your point.
I'm not making a point. There is no debate. You said you want to work on unions, that would be great. But this is a cut and dried area. There's no room for creativity here. If you want to be creative and design new programming language facilities, do something else. For unions do what needs be done.
That is dishonest. First because there is almost no spec - so there is much to debate, second because what you propose is different from what is describe in the little spec there is (literally, no postblit/destructor in the union or its elements is the only that is specified). Please stop projecting. You are the one being creative here.
Jun 01 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/1/15 9:46 PM, deadalnix wrote:
 No, I asked you what is the rationale used to get types with
 postblit/destructor in unions (right now, the spec says no). I asked
 about the rationale for introduction of element with destructor/copy
 constructor in C++, but it turns out that the link provided also include
 constructor, and, in fact, only explore the constructor case in the
 rationale.
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2248.html: ======== Unfortunately this brute-force approach cannot be extended to every user-defined type that a programmer might want to pass around transparently. As class types, unions are definitely second class: although a union may define a constructor and destructor for instances of its type, the standard does not allow it to contain any member whose default constructor, copy constructor, copy assignment operator, or destructor are non-trivial. The reason for these tight restrictions is obvious -- the compiler can hardly be expected to generate sensible default special member functions for an object whose type will only become known at run time, and therefore a "lowest-common-denominator" policy applies. With the rules in place, default initialization is effectively a no-op, likewise destruction, and copying is performed using a low-level memcpy. This rules out the inclusion of "interesting" types, or else requires the programmer to ignore good design practice in order to make them conform to the straightjacket of trivial types (see discussion in N2172). And yet the need for a "variant" data structure that can hold one object of a set of unrelated types is a problem that arises over and over [...] ======== There are others to be found in related docs. The simple explanation is that non-discriminated unions are most useful as unstructured bags that allow their users to plant their own types in whilst keeping their discriminant elsewhere. Planting either gratuitous restrictions on the storable data, or smarts regarding construction and destruction, simply reduces the range of things that unions are good at. I don't know how to explain this better.
 It is important to consider why C++ did something to know if it makes
 sense to import it in D. I remind you that this is a change that you
 propose to the current state of affairs, meaning the burden of proof in
 on you.
Fair enough.
 Then again sorry I am misunderstanding something. I'm saying the right
 way to go is unions accept all types.
You are saying this. Many on that thread said otherwise. I personally have no strong opinion one way or another. That is why I'm asking about what makes you think element with postblit/destructor needs to be accepted in unions, in order to have all elements I needs to have an informed opinion.
The same explanation as above stands. Andrei
Jun 01 2015
parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 2 June 2015 at 05:07:43 UTC, Andrei Alexandrescu 
wrote:
 On 6/1/15 9:46 PM, deadalnix wrote:
 No, I asked you what is the rationale used to get types with
 postblit/destructor in unions (right now, the spec says no). I 
 asked
 about the rationale for introduction of element with 
 destructor/copy
 constructor in C++, but it turns out that the link provided 
 also include
 constructor, and, in fact, only explore the constructor case 
 in the
 rationale.
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2248.html: ======== Unfortunately this brute-force approach cannot be extended to every user-defined type that a programmer might want to pass around transparently. As class types, unions are definitely second class: although a union may define a constructor and destructor for instances of its type, the standard does not allow it to contain any member whose default constructor, copy constructor, copy assignment operator, or destructor are non-trivial. The reason for these tight restrictions is obvious -- the compiler can hardly be expected to generate sensible default special member functions for an object whose type will only become known at run time, and therefore a "lowest-common-denominator" policy applies. With the rules in place, default initialization is effectively a no-op, likewise destruction, and copying is performed using a low-level memcpy. This rules out the inclusion of "interesting" types, or else requires the programmer to ignore good design practice in order to make them conform to the straightjacket of trivial types (see discussion in N2172). And yet the need for a "variant" data structure that can hold one object of a set of unrelated types is a problem that arises over and over [...] ======== There are others to be found in related docs. The simple explanation is that non-discriminated unions are most useful as unstructured bags that allow their users to plant their own types in whilst keeping their discriminant elsewhere. Planting either gratuitous restrictions on the storable data, or smarts regarding construction and destruction, simply reduces the range of things that unions are good at. I don't know how to explain this better.
It is unfortunate that the explanation do not go over the constructor but no desturctor case (way more common in D than in C++). I think the case is not as strong for D, as a we already allow struct with constructor, contrary to C++ when this document was done. Still probably the right way forward, granted this is system. When you are in union land, you are pretty much on your own anyway.
Jun 02 2015
prev sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 2 June 2015 at 05:00, deadalnix via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 After discussion at DConf, it ends up that union have some lack of
 specification, and some nonsensical behavior right now. Here are some points
 discussed and possible solutions :

 1/ .init for unions is not defined. I propose to define it as the .init of
 the first field + padding with 0s if the union is larger than its first
 member. It seems to be what is generated right now.
Isn't it the case that some of the members of a union need to be declared with init =void, such that only one version of the union provides the init values? At that point, isn't the state of init clearly defined by the members that aren't =void?
Jun 02 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/2/15 1:48 AM, Manu via Digitalmars-d wrote:
 On 2 June 2015 at 05:00, deadalnix via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 After discussion at DConf, it ends up that union have some lack of
 specification, and some nonsensical behavior right now. Here are some points
 discussed and possible solutions :

 1/ .init for unions is not defined. I propose to define it as the .init of
 the first field + padding with 0s if the union is larger than its first
 member. It seems to be what is generated right now.
Isn't it the case that some of the members of a union need to be declared with init =void, such that only one version of the union provides the init values? At that point, isn't the state of init clearly defined by the members that aren't =void?
That could be done, but strikes me as too clever for its own good. -- Andrei
Jun 02 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/2/15 6:50 PM, Andrei Alexandrescu wrote:
 On 6/2/15 1:48 AM, Manu via Digitalmars-d wrote:
 On 2 June 2015 at 05:00, deadalnix via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 After discussion at DConf, it ends up that union have some lack of
 specification, and some nonsensical behavior right now. Here are some
 points
 discussed and possible solutions :

 1/ .init for unions is not defined. I propose to define it as the
 .init of
 the first field + padding with 0s if the union is larger than its first
 member. It seems to be what is generated right now.
Isn't it the case that some of the members of a union need to be declared with init =void, such that only one version of the union provides the init values? At that point, isn't the state of init clearly defined by the members that aren't =void?
That could be done, but strikes me as too clever for its own good. -- Andrei
It's actually unnecessarily redundant. In all cases, you can simply move the "valid" one to the first member. Initing the first member is the right call. -Steve
Jun 02 2015
prev sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 3 June 2015 at 08:50, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 6/2/15 1:48 AM, Manu via Digitalmars-d wrote:
 On 2 June 2015 at 05:00, deadalnix via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 After discussion at DConf, it ends up that union have some lack of
 specification, and some nonsensical behavior right now. Here are some
 points
 discussed and possible solutions :

 1/ .init for unions is not defined. I propose to define it as the .init
 of
 the first field + padding with 0s if the union is larger than its first
 member. It seems to be what is generated right now.
Isn't it the case that some of the members of a union need to be declared with init =void, such that only one version of the union provides the init values? At that point, isn't the state of init clearly defined by the members that aren't =void?
That could be done, but strikes me as too clever for its own good. -- Andrei
Right. See, I thought that's just how it already was ;) I recall writing some union code and having compile errors, and being required to resolve it by setting =void to all the members in conflict, effectively making the initialisation of the union explicit.
Jun 02 2015