www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - copy-ctor's

reply Manu <turkeyman gmail.com> writes:
So, it seems that if an object has a postblit and a copy constructor,
the postblit is preferred.

It also seems that if an object has a copy constructor and a MEMBER
with a postblit, then object has a postblit generated which calls
through to the member, and that is preferred.

I have also noticed that if you have a union containing an item with a
postblit, the postblit is always called, even if the item in the union
is not valid:

struct S(T)
{
  union {
    int x = 0;
    T y = void;
  }
  bool isT = false;
}

S a;
S b = a; // calls `y's postblit, even though it's `isT` is false and
the object is `void` initialised...

So, it's very hard to craft a tool like 'S', when the supplied T might
have a postblit and ruin everything. What are my options here?

Also, `hasElaborateCopyConstructor` is broken now. It should know
about copy ctor's.
May 25
next sibling parent Exil <Exil gmall.com> writes:
On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:
 So, it seems that if an object has a postblit and a copy 
 constructor, the postblit is preferred.

 It also seems that if an object has a copy constructor and a 
 MEMBER with a postblit, then object has a postblit generated 
 which calls through to the member, and that is preferred.

 I have also noticed that if you have a union containing an item 
 with a postblit, the postblit is always called, even if the 
 item in the union is not valid:

 struct S(T)
 {
   union {
     int x = 0;
     T y = void;
   }
   bool isT = false;
 }

 S a;
 S b = a; // calls `y's postblit, even though it's `isT` is 
 false and
 the object is `void` initialised...

 So, it's very hard to craft a tool like 'S', when the supplied 
 T might have a postblit and ruin everything. What are my 
 options here?

 Also, `hasElaborateCopyConstructor` is broken now. It should 
 know about copy ctor's.
Seems a union also calls the postblit for every object in a union, which makes less sense, since only one of them should be valid at a time. IIRC there was also a problem with copy constructors conflicting with the default constructor initalizers. Would probably be best to iron out all these bugs now before it gets used too much.
May 25
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:
 So, it seems that if an object has a postblit and a copy 
 constructor, the postblit is preferred.
Correct, that is the transitional behaviour until postblit is truly dead.
 It also seems that if an object has a copy constructor and a 
 MEMBER with a postblit, then object has a postblit generated 
 which calls through to the member, and that is preferred.
Thats probably a bit of a grey area. I'll defer to Razvan for that one.
 I have also noticed that if you have a union containing an item 
 with a postblit, the postblit is always called, even if the 
 item in the union is not valid:
Thats a bug.
 So, it's very hard to craft a tool like 'S', when the supplied 
 T might have a postblit and ruin everything. What are my 
 options here?
File a bug report and ensure that Razvan Nitu is CC'd.
 Also, `hasElaborateCopyConstructor` is broken now. It should 
 know about copy ctor's.
https://run.dlang.io/gist/71e722a80b5a9ab54625508915bc7738?compiler=dmd-beta _almost_ does it, I'm not quite sure what I'm missing though.
May 25
parent reply Manu <turkeyman gmail.com> writes:
On Sat, May 25, 2019 at 9:15 PM Nicholas Wilson via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:
 So, it seems that if an object has a postblit and a copy
 constructor, the postblit is preferred.
Correct, that is the transitional behaviour until postblit is truly dead.
Right, but it's not a helpful behaviour; it undermines copy ctors... in my example above, 'S' can't control the template argument, which means `T` may have a postblit and so `S` can't possibly be written to work.
 I have also noticed that if you have a union containing an item
 with a postblit, the postblit is always called, even if the
 item in the union is not valid:
Thats a bug.
Indeed. I also noticed another one; it doesn't just call postblit's for each item in the union, it also calls destructors for each item in the union! O_O How has this issue never come up?
 So, it's very hard to craft a tool like 'S', when the supplied
 T might have a postblit and ruin everything. What are my
 options here?
File a bug report and ensure that Razvan Nitu is CC'd.
I don't know his email address... that CC box seems to work by email addresses.
May 26
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 26 May 2019 at 20:38:48 UTC, Manu wrote:
 item in the union, it also calls destructors for each item in 
 the
 union! O_O
 How has this issue never come up?
It has, since 2010? https://forum.dlang.org/search?q=union%20destructors
May 26
next sibling parent Manu <turkeyman gmail.com> writes:
Haha, and I'm the OP... not surprised at all ;)

On Sun, May 26, 2019 at 2:40 PM Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 26 May 2019 at 20:38:48 UTC, Manu wrote:
 item in the union, it also calls destructors for each item in
 the
 union! O_O
 How has this issue never come up?
It has, since 2010? https://forum.dlang.org/search?q=union%20destructors
May 26
prev sibling parent reply Manu <turkeyman gmail.com> writes:
Oh, no.. that's search results, listed recent first. I didn't realise
the forum could do that.

On Sun, May 26, 2019 at 3:32 PM Manu <turkeyman gmail.com> wrote:
 Haha, and I'm the OP... not surprised at all ;)

 On Sun, May 26, 2019 at 2:40 PM Ola Fosheim Grøstad via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On Sunday, 26 May 2019 at 20:38:48 UTC, Manu wrote:
 item in the union, it also calls destructors for each item in
 the
 union! O_O
 How has this issue never come up?
It has, since 2010? https://forum.dlang.org/search?q=union%20destructors
May 26
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 26 May 2019 at 22:33:48 UTC, Manu wrote:
 Oh, no.. that's search results, listed recent first. I didn't 
 realise the forum could do that.
Oh yes, that can be confusing. Untagged unions doesn't really play well with destructors in any language. I think C++ requires that those destructors are ignored and that the union's destructor should do the cleanup. Seems like a thing that is easy to forget though…
May 26
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Sunday, 26 May 2019 at 23:45:05 UTC, Ola Fosheim Grøstad wrote:
 On Sunday, 26 May 2019 at 22:33:48 UTC, Manu wrote:
 Oh, no.. that's search results, listed recent first. I didn't 
 realise the forum could do that.
Oh yes, that can be confusing. Untagged unions doesn't really play well with destructors in any language. I think C++ requires that those destructors are ignored and that the union's destructor should do the cleanup. Seems like a thing that is easy to forget though…
I vaguely remember Bearophile suggest that the union/struct should provide a means to identify which type the union was holding. One usually has a union in a struct that also contains a tag of some sort that signifies the type of the union… but I think this is outside the scope of D as a language. So perhaps one should not be allowed to have destructors in untagged unions and encourage the use of tagged unions…
May 26
parent reply Manu <turkeyman gmail.com> writes:
On Sun, May 26, 2019 at 4:55 PM Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 26 May 2019 at 23:45:05 UTC, Ola Fosheim Grøstad wrote:
 On Sunday, 26 May 2019 at 22:33:48 UTC, Manu wrote:
 Oh, no.. that's search results, listed recent first. I didn't
 realise the forum could do that.
Oh yes, that can be confusing. Untagged unions doesn't really play well with destructors in any language. I think C++ requires that those destructors are ignored and that the union's destructor should do the cleanup. Seems like a thing that is easy to forget though…
I vaguely remember Bearophile suggest that the union/struct should provide a means to identify which type the union was holding. One usually has a union in a struct that also contains a tag of some sort that signifies the type of the union… but I think this is outside the scope of D as a language. So perhaps one should not be allowed to have destructors in untagged unions and encourage the use of tagged unions…
Well I'm obviously implementing a tagged union. The language just needs to make the feature available, and let me wrap it up. The proper thing to do here, is disable field-copy/destruction for items in unions, and if the owning type doesn't declare copy-ctor/destructors, then the default functions should be disabled rather than generated from fields as usual. It should also be un- safe to reference a member of a union from any method, and from there we have everything we need to write tooling.
May 26
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 27 May 2019 at 00:41:22 UTC, Manu wrote:
 Well I'm obviously implementing a tagged union.
 The language just needs to make the feature available, and let 
 me wrap it up.
IIRC Bearophile suggested that the struct could provide a function or some mechanism that would tell the runtime what type the union contained. But Andrei didn't like it. Some sort of "type-switch" statement in the union with a conditional that is allowed to reference fields in the surrounding struct would be a possibility. The real problem isn't that one cannot come up with a decent solution, but that the semantics of C has been subsumed, and extended.
May 26
parent reply Manu <turkeyman gmail.com> writes:
On Sun, May 26, 2019 at 7:55 PM Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Monday, 27 May 2019 at 00:41:22 UTC, Manu wrote:
 Well I'm obviously implementing a tagged union.
 The language just needs to make the feature available, and let
 me wrap it up.
IIRC Bearophile suggested that the struct could provide a function or some mechanism that would tell the runtime what type the union contained. But Andrei didn't like it.
Right, that's a terrible idea. Who's to say that's how the union is used.
 Some sort of "type-switch" statement in the union with a
 conditional that is allowed to reference fields in the
 surrounding struct would be a possibility.
Sounds like a lib to me.
 The real problem isn't that one cannot come up with a decent
 solution, but that the semantics of C has been subsumed, and
 extended.
I don't really think there's a problem here, just disable the default copy/postblit/destructor in the presence of a union, and also make any access to a member of a union un- safe. The rest will fall out naturally.
May 26
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 27 May 2019 at 04:52:14 UTC, Manu wrote:
 I don't really think there's a problem here, just  disable the 
 default copy/postblit/destructor in the presence of a union, 
 and also make any access to a member of a union un- safe. The 
 rest will fall out naturally.
Depends on how strict you want to be. In terms of correctness you shouldn't allow anything with a destructor in a union in the first place.
May 26
parent Manu <turkeyman gmail.com> writes:
On Sun, May 26, 2019 at 10:20 PM Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Monday, 27 May 2019 at 04:52:14 UTC, Manu wrote:
 I don't really think there's a problem here, just  disable the
 default copy/postblit/destructor in the presence of a union,
 and also make any access to a member of a union un- safe. The
 rest will fall out naturally.
Depends on how strict you want to be. In terms of correctness you shouldn't allow anything with a destructor in a union in the first place.
Why? Then it would be impossible to use unions to write anything useful.
May 26
prev sibling next sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:
 So, it seems that if an object has a postblit and a copy 
 constructor, the postblit is preferred.

 It also seems that if an object has a copy constructor and a 
 MEMBER with a postblit, then object has a postblit generated 
 which calls through to the member, and that is preferred.

 I have also noticed that if you have a union containing an item 
 with a postblit, the postblit is always called, even if the 
 item in the union is not valid:
That's a bug, but I think that it's not going to be fixed since the postblit should be deprecated soon.
 struct S(T)
 {
   union {
     int x = 0;
     T y = void;
   }
   bool isT = false;
 }

 S a;
 S b = a; // calls `y's postblit, even though it's `isT` is 
 false and
 the object is `void` initialised...

 So, it's very hard to craft a tool like 'S', when the supplied 
 T might have a postblit and ruin everything. What are my 
 options here?
Currently, you don't have any options. As I see it, there are 3 possible solutions: 1. Change the semantics of `disable this(this)` from "object is not copyable" to "object is not copyable through postblit". This way we can exclude postblits but allow copies using the copy constructor. 2. Check if T has postblit with a static if (via traits) and define the copy constructor only if T does not have a postblit. 3. Issue a deprecation if T has a postblit. Essentially, there is no clear way in how you can mix object with postblits and objects with copy constructor
 Also, `hasElaborateCopyConstructor` is broken now. It should 
 know about copy ctor's.
May 27
parent Manu <turkeyman gmail.com> writes:
On Mon, May 27, 2019 at 2:11 AM RazvanN via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:
 So, it seems that if an object has a postblit and a copy
 constructor, the postblit is preferred.

 It also seems that if an object has a copy constructor and a
 MEMBER with a postblit, then object has a postblit generated
 which calls through to the member, and that is preferred.

 I have also noticed that if you have a union containing an item
 with a postblit, the postblit is always called, even if the
 item in the union is not valid:
That's a bug, but I think that it's not going to be fixed since the postblit should be deprecated soon.
How soon? Is this another case of "just wait 10 more years before you can use D"? It looks like it needed to be fixed about 10 years ago, so no time like the present! :)
 struct S(T)
 {
   union {
     int x = 0;
     T y = void;
   }
   bool isT = false;
 }

 S a;
 S b = a; // calls `y's postblit, even though it's `isT` is
 false and
 the object is `void` initialised...

 So, it's very hard to craft a tool like 'S', when the supplied
 T might have a postblit and ruin everything. What are my
 options here?
Currently, you don't have any options. As I see it, there are 3 possible solutions: 1. Change the semantics of `disable this(this)` from "object is not copyable" to "object is not copyable through postblit". This way we can exclude postblits but allow copies using the copy constructor.
Good idea, and easy to implement in minutes! It's not a solution though, but it is one piece in a larger puzzle.
 2. Check if T has postblit with a static if (via traits) and
 define the copy
 constructor only if T does not have a postblit.
This is useless, because if S does not have a copy constructor, the object can't work under any circumstances. It also wouldn't solve the problem, since the union item's destructor is still called by the same rules, so copying is not the only issue here.
 3. Issue a deprecation if T has a postblit.

 Essentially, there is no clear way in how you can mix object with
 postblits and objects with copy constructor
Right, they shouldn't be mixed. In this case, I could move forwards if the union issue was fixed though. If T in the union did NOT call field-copy and field-destruction (which is just a bug!), then I could static-check and manually handle the 2 cases of whether T has a copyctor or a postblit in the implementation of the copy ctor of S, so I could reconcile the difference with some extra work in S. I think the only path to solution is to fix the issue with unions, and that absolutely needs to happen anyway regardless.
May 27
prev sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:

 I have also noticed that if you have a union containing an item 
 with a postblit, the postblit is always called, even if the 
 item in the union is not valid:
Just for the record, I've made a PR that fixes this: https://github.com/dlang/dmd/pull/9909 Hope this will be of help for you, Manu.
May 28
parent Manu <turkeyman gmail.com> writes:
On Tue, May 28, 2019 at 6:30 AM RazvanN via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Saturday, 25 May 2019 at 23:15:05 UTC, Manu wrote:

 I have also noticed that if you have a union containing an item
 with a postblit, the postblit is always called, even if the
 item in the union is not valid:
Just for the record, I've made a PR that fixes this: https://github.com/dlang/dmd/pull/9909 Hope this will be of help for you, Manu.
OMG so good! Bonus points if any access to members of a union is un- safe...
May 28