www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP 1018--The Copy Constructor--Community Review Round 1

reply Mike Parker <aldacron gmail.com> writes:
This is the feedback thread for the first round of Community 
Review for DIP 1018, "The Copy Constructor":

https://github.com/dlang/DIPs/blob/07da1f2cabc8b1bc3ad66034598a133e5ad13356/DIPs/DIP1018.md

All review-related feedback on and discussion of the DIP should 
occur in this thread. The review period will end at 11:59 PM ET 
on January 4, or when I make a post declaring it complete. (This 
time I'm extending the review period by a few days because of the 
holidays.)

At the end of Round 1, if further review is deemed necessary, the 
DIP will be scheduled for another round of community review. 
Otherwise, it will be queued for the Final Review and Formal 
Assessment by the language maintainers.

Please familiarize yourself with the documentation for the 
Community Review before participating.

https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review

Thanks in advance to all who participate.
Dec 18 2018
next sibling parent reply Kagamin <spam here.lot> writes:
I think const postblit can be done by creating shadow copy of 
instance fields (but still physically located in the field).

struct A
{
     int b;
     this(this) immutable
     {
         immutable int shadow_b; //reads go here
         //b++
         immutable int t=shadow_b;
         shadow_b.__dtor();
         b.__ctor(t+1);
     }
}

Type system would treat them as distinct instances, but would 
destroy shadow copy right before assignment, after which shadow 
copy's lifetime ends and it goes out of scope completely, which 
will also invalidate any retained pointers if any.
Dec 19 2018
next sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Wednesday, 19 December 2018 at 11:53:12 UTC, Kagamin wrote:
 I think const postblit can be done by creating shadow copy of 
 instance fields (but still physically located in the field).

 struct A
 {
     int b;
     this(this) immutable
     {
         immutable int shadow_b; //reads go here
         //b++
         immutable int t=shadow_b;
         shadow_b.__dtor();
         b.__ctor(t+1);
     }
 }

 Type system would treat them as distinct instances, but would 
 destroy shadow copy right before assignment, after which shadow 
 copy's lifetime ends and it goes out of scope completely, which 
 will also invalidate any retained pointers if any.
This makes the blitting useless. Look at it this way: the compiler blitts the struct (in this case, `b`), then it makes another copy of it (`immutable int t = b) solely for the purpose of destroying the field for the former instance (!!!!!!). All this copies become useless when using the copy constructor. Cheers, RazvanN
Dec 19 2018
parent reply Kagamin <spam here.lot> writes:
On Wednesday, 19 December 2018 at 13:40:41 UTC, RazvanN wrote:
 All this copies become useless when using the copy constructor.
A copy constructor is very verbose though, imagine a copy constructor for a struct with 30 fields, where it copies 29 fields and sets the 30th to null. Postblit is observation of pattern that copy constructor usually changes only a small part of the struct. In this synthetic example copying wouldn't make much difference: for this code: --- struct A { int b; void inc() { const int shadow_b=b; //b++ const int t=shadow_b; b=t+1; } } A f(ref A a) { A b=a; b.inc(); return b; } --- `ldc -Os` generates this code for function f: --- movl (%rdi), %eax addl $1, %eax retq ---
Dec 20 2018
next sibling parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Thursday, 20 December 2018 at 14:41:49 UTC, Kagamin wrote:
 On Wednesday, 19 December 2018 at 13:40:41 UTC, RazvanN wrote:
 [...]
A copy constructor is very verbose though, imagine a copy constructor for a struct with 30 fields, where it copies 29 fields and sets the 30th to null.
For that you can use metaprogramming: static foreach (i, ref field; src.tupleof) this.tupleof[i] = field; this.field_of_choice = null;
  Postblit is observation of pattern that copy constructor 
 usually changes only a small part of the struct. In this 
 synthetic example copying wouldn't make much difference:
 for this code:
 ---
 struct A
 {
     int b;
     void inc()
     {
         const int shadow_b=b;
         //b++
         const int t=shadow_b;
         b=t+1;
     }
 }

 A f(ref A a)
 {
     A b=a;
     b.inc();
     return b;
 }
 ---
 `ldc -Os` generates this code for function f:
 ---
 	movl	(%rdi), %eax
 	addl	$1, %eax
 	retq
 ---
Dec 20 2018
prev sibling parent reply Neia Neutuladh <neia ikeran.org> writes:
On Thu, 20 Dec 2018 14:41:49 +0000, Kagamin wrote:
 On Wednesday, 19 December 2018 at 13:40:41 UTC, RazvanN wrote:
 All this copies become useless when using the copy constructor.
A copy constructor is very verbose though, imagine a copy constructor for a struct with 30 fields, where it copies 29 fields and sets the 30th to null.
this.tupleof = other.tupleof; this.field30 = null; Pretty succinct.
Dec 20 2018
parent reply Kagamin <spam here.lot> writes:
On Thursday, 20 December 2018 at 16:53:29 UTC, Neia Neutuladh 
wrote:
 this.tupleof = other.tupleof;
 this.field30 = null;
This will initialize field30 twice, won't it?
Dec 21 2018
parent Johannes Loher <johannes.loher fg4f.de> writes:
On Friday, 21 December 2018 at 12:01:49 UTC, Kagamin wrote:
 On Thursday, 20 December 2018 at 16:53:29 UTC, Neia Neutuladh 
 wrote:
 this.tupleof = other.tupleof;
 this.field30 = null;
This will initialize field30 twice, won't it?
Indeed. What happens if field30 is const?
Dec 22 2018
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 19 December 2018 at 11:53:12 UTC, Kagamin wrote:
 I think const postblit can be done by creating shadow copy of 
 instance fields (but still physically located in the field).

 struct A
 {
     int b;
     this(this) immutable
     {
         immutable int shadow_b; //reads go here
         //b++
         immutable int t=shadow_b;
         shadow_b.__dtor();
         b.__ctor(t+1);
     }
 }

 Type system would treat them as distinct instances, but would 
 destroy shadow copy right before assignment, after which shadow 
 copy's lifetime ends and it goes out of scope completely, which 
 will also invalidate any retained pointers if any.
You should not be resorting to calling the hidden symbol .__dtor, .__ctor in your production code as that is just asking for trouble. Which it is not guarantee to grant the behavior that you desire. Alex
Dec 19 2018
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Wednesday, 19 December 2018 at 14:34:37 UTC, 12345swordy wrote:
 On Wednesday, 19 December 2018 at 11:53:12 UTC, Kagamin wrote:
 [...]
You should not be resorting to calling the hidden symbol .__dtor, .__ctor in your production code as that is just asking for trouble. Which it is not guarantee to grant the behavior that you desire. Alex
I think that he was suggesting that that is compiler generated code.
Dec 20 2018
prev sibling next sibling parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor"
1). I do not like the ability to specify a mutable copy source. Under no circumstance should the code like A a; A fun() { return a; // lowered to return tmp.copyCtor(a) } void main() { A b = fun(); // the return value of fun() is moved to the location of b } be allowed to modify the value of a. This is an absolute pain to read\debug, and I would instead like to see a mandatory const\immutable on the source reference. Copy operation should not modify the source, or it should not be called a copy. If we are talking about a typical smart pointer struct (Refcounted), copy still should not modify the source. It is D's transitive const\immutable that is a problem here and it must be explicitly casted away by the developer. Only const also mitigates the combinatorial mess caused by 4 combinations of mutable\immutable copy constructors, since immutable is implicitly converted to const. 2). "A declaration is a copy constructor declaration if it is a constructor declaration that takes only one non-default parameter by reference that is of the same type as typeof(this), followed by any number of default parameters..." If you need other parameters, you are not performing a copy. Copy constructor needs no additional parameters. If the semantics of your domain problem involve parametrized post-copy operations, the code should state that explicitly - by using specialized properly-named methods, that notify the reader about this particularity. 3). Section "Copy constructor usage", I don't understand the difference: void main() { A a; A b = a; // copy constructor gets called b = a; // assignment, not initialization } and void main() { A a; a = fun(); // NRVO - no copy constructor call A b; // b is initialized after this semicolon. // why is this one not an assignment, but initialization? // do we have the difference formally and consistently defined for structs? b = gun(); // NRVO cannot be performed, copy constructor is called }
Dec 21 2018
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 21, 2018 at 02:43:50PM +0000, Boris-Barboris via Digitalmars-d
wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community Review for
 DIP 1018, "The Copy Constructor"
1). I do not like the ability to specify a mutable copy source. Under no circumstance should the code like A a; A fun() { return a; // lowered to return tmp.copyCtor(a) } void main() { A b = fun(); // the return value of fun() is moved to the location of b } be allowed to modify the value of a. This is an absolute pain to read\debug, and I would instead like to see a mandatory const\immutable on the source reference. Copy operation should not modify the source, or it should not be called a copy. If we are talking about a typical smart pointer struct (Refcounted), copy still should not modify the source. It is D's transitive const\immutable that is a problem here and it must be explicitly casted away by the developer. Only const also mitigates the combinatorial mess caused by 4 combinations of mutable\immutable copy constructors, since immutable is implicitly converted to const.
Shouldn't const be inout in this case?
 2). "A declaration is a copy constructor declaration if it is a
 constructor declaration that takes only one non-default parameter by
 reference that is of the same type as typeof(this), followed by any
 number of default parameters..."
 
 If you need other parameters, you are not performing a copy. Copy
 constructor needs no additional parameters. If the semantics of your
 domain problem involve parametrized post-copy operations, the code
 should state that explicitly - by using specialized properly-named
 methods, that notify the reader about this particularity.
[...] +1. Doing otherwise adds needless complexity for something I can't think of any use cases for. -- Programming is not just an act of telling a computer what to do: it is also an act of telling other programmers what you wished the computer to do. Both are important, and the latter deserves care. -- Andrew Morton
Dec 21 2018
parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Friday, 21 December 2018 at 21:40:23 UTC, H. S. Teoh wrote:
 Shouldn't const be inout in this case?
Just in case: it's not my code, it's from the DIP example snippets. I was advocating for forbidden mutable copy source. Inout indeed solves the boilerplate/combinatorial problem, but my main conjecture was about readability, wich is harmed by mutable source default.
Dec 21 2018
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
wrote:
 On Friday, 21 December 2018 at 21:40:23 UTC, H. S. Teoh wrote:
 Shouldn't const be inout in this case?
Just in case: it's not my code, it's from the DIP example snippets. I was advocating for forbidden mutable copy source. Inout indeed solves the boilerplate/combinatorial problem, but my main conjecture was about readability, wich is harmed by mutable source default.
One of the primary use cases for this is ref-counting stuff, the refcount needs to be mutable.
Dec 21 2018
parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Saturday, 22 December 2018 at 02:02:55 UTC, Nicholas Wilson 
wrote:
 On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
 wrote:

 One of the primary use cases for this is ref-counting stuff, 
 the refcount needs to be mutable.
I thought ref-counted stuff is perfectly fine with postblits, was I wrong?
Dec 22 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Saturday, 22 December 2018 at 09:07:52 UTC, Boris-Barboris 
wrote:
 On Saturday, 22 December 2018 at 02:02:55 UTC, Nicholas Wilson 
 wrote:
 On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
 wrote:

 One of the primary use cases for this is ref-counting stuff, 
 the refcount needs to be mutable.
I thought ref-counted stuff is perfectly fine with postblits, was I wrong?
Nope, it turns out you can't implement ref-counting GC with postbilts. Andrei have tried to do this already and failed. That why they are introducing it, (and why it should be covered in the motivation section in the DIP).
Dec 22 2018
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 22 December 2018 at 14:43:46 UTC, 12345swordy wrote:
 On Saturday, 22 December 2018 at 09:07:52 UTC, Boris-Barboris 
 wrote:
 On Saturday, 22 December 2018 at 02:02:55 UTC, Nicholas Wilson 
 wrote:
 On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
 wrote:

 One of the primary use cases for this is ref-counting stuff, 
 the refcount needs to be mutable.
I thought ref-counted stuff is perfectly fine with postblits, was I wrong?
Nope, it turns out you can't implement ref-counting GC with postbilts. Andrei have tried to do this already and failed. That why they are introducing it, (and why it should be covered in the motivation section in the DIP).
The motivation section, although it does not link to the RC GC, it describes the problems encountered when trying to implement it. The main problem was the fact that when dealing with immutable fields, after the blitting phase is done it is not obvious in what state the immutable fields is (raw/cooked?).
Jan 05
prev sibling parent reply Rubn <where is.this> writes:
On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
wrote:
 On Friday, 21 December 2018 at 21:40:23 UTC, H. S. Teoh wrote:
 Shouldn't const be inout in this case?
Just in case: it's not my code, it's from the DIP example snippets. I was advocating for forbidden mutable copy source. Inout indeed solves the boilerplate/combinatorial problem, but my main conjecture was about readability, wich is harmed by mutable source default.
The DIP goes over why const wasn't used for the source. Consider the following: struct A { int* ptr; } Now to simulate the copy constructor: A copy(ref const A a) { A result; result.ptr = a.ptr; // error can't convert `const int*` to `int*` return result; } Const is infectious and just causes more problems making it pretty much useless in the general case. It's only suitable for a very narrow use case. A lot of people using D avoid const entirely, except for really basic simple things involving primitive types.
Dec 21 2018
parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Saturday, 22 December 2018 at 03:37:22 UTC, Rubn wrote:
 On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
 wrote:

 The DIP goes over why const wasn't used for the source. 
 Consider the following:

 struct A {
     int* ptr;
 }

 Now to simulate the copy constructor:

 A copy(ref const A a) {
     A result;
     result.ptr = a.ptr; // error can't convert `const int*` to 
 `int*`
     return result;
 }

 Const is infectious and just causes more problems making it 
 pretty much useless in the general case. It's only suitable for 
 a very narrow use case. A lot of people using D avoid const 
 entirely, except for really basic simple things involving 
 primitive types.
Exactly my intent, to cause problems in this case and force a cast. For example, your code is actually not performing a copy of A. Your copy constructor is making a shallow copy, by duplicating only one vertex of the memory graph. If you were actually copying it, you would allocate a new int on the heap and initializa it from the const source.ptr without a problem. Current blitting is perfect for shallow copies as it is. If we are to give default semantical meaning to the copy constructor, that the programmer can generally rely on in the unfamiliar codebase, we need to restrict the developer. If we are to give it a semantic meaning of the function where you do whatever you want with source and dest, why should we call it a COPY constructor?
Dec 22 2018
parent Rubn <where is.this> writes:
On Saturday, 22 December 2018 at 09:01:09 UTC, Boris-Barboris 
wrote:
 On Saturday, 22 December 2018 at 03:37:22 UTC, Rubn wrote:
 On Saturday, 22 December 2018 at 00:08:51 UTC, Boris-Barboris 
 wrote:

 The DIP goes over why const wasn't used for the source. 
 Consider the following:

 struct A {
     int* ptr;
 }

 Now to simulate the copy constructor:

 A copy(ref const A a) {
     A result;
     result.ptr = a.ptr; // error can't convert `const int*` to 
 `int*`
     return result;
 }

 Const is infectious and just causes more problems making it 
 pretty much useless in the general case. It's only suitable 
 for a very narrow use case. A lot of people using D avoid 
 const entirely, except for really basic simple things 
 involving primitive types.
Exactly my intent, to cause problems in this case and force a cast. For example, your code is actually not performing a copy of A. Your copy constructor is making a shallow copy, by duplicating only one vertex of the memory graph. If you were actually copying it, you would allocate a new int on the heap and initializa it from the const source.ptr without a problem. Current blitting is perfect for shallow copies as it is.
Blitting can't copy from one object type to another though. This constructor will be able to do that.
 If we are to give default semantical meaning to the copy 
 constructor, that the programmer can generally rely on in the 
 unfamiliar codebase, we need to restrict the developer. If we 
 are to give it a semantic meaning of the function where you do 
 whatever you want with source and dest, why should we call it a 
 COPY constructor?
Sure it's not a very accurate name, changing the name to be something else is fine. Just don't change the implementation to require const and make it that much harder to use.
Dec 22 2018
prev sibling next sibling parent reply Johannes Loher <johannes.loher fg4f.de> writes:
On Friday, 21 December 2018 at 14:43:50 UTC, Boris-Barboris wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 1). I do not like the ability to specify a mutable copy source. 
 Under no circumstance should the code like

 A a;
 A fun()
 {
     return a;      // lowered to return tmp.copyCtor(a)
 }

 void main()
 {
     A b = fun();    // the return value of fun() is moved to 
 the location of b
 }

 be allowed to modify the value of a.
I totally agree. A copy modifying the source is very counter intuitive.
 2). "A declaration is a copy constructor declaration if it is a 
 constructor declaration that takes only one non-default 
 parameter by reference that is of the same type as 
 typeof(this), followed by any number of default parameters..."

 If you need other parameters, you are not performing a copy. 
 Copy constructor needs no additional parameters. If the 
 semantics of your domain problem involve parametrized post-copy 
 operations, the code should state that explicitly - by using 
 specialized properly-named methods, that notify the reader 
 about this particularity.
I also agree with this. It is not even possible to pass something to the additional (default) parameters if not calling the Copy constructor explicitly, is it? ``` struct A { this(ref A src, int b = 0) {} } void main() { A a; auto b = a; // How to pass something as b? auto c = A(a, 1); // Works in this case } ```
 3). Section "Copy constructor usage", I don't understand the 
 difference:

 void main()
 {
     A a;
     A b = a; // copy constructor gets called
     b = a;   // assignment, not initialization
 }

 and

 void main()
 {
     A a;
     a = fun();      // NRVO - no copy constructor call
     A b; // b is initialized after this semicolon.
     // why is this one not an assignment, but initialization?
     // do we have the difference formally and consistently 
 defined for structs?
     b = gun();      // NRVO cannot be performed, copy 
 constructor is called
 }
I believe the first case is straight forward, so your confusion probably stems from the second case: In the main function, we do have assignments to a and b. Those are not initializations and so no copy construction is taking place because of this. But when functions return, if NRVO (named return value optimization) cannot be performed, a copy of their return value is created. This happens in the case of gun because a is a module level variable and so NRVO cannot be performed. I believe this example is indeed a bit confusing, mostly because the DIP does not at all explain what actually happens here and only uses the cryptic acronym NRVO. I believe a more detailed description is needed here, maybe in conjunction with a comparison to how this example would work with postblit.
Dec 22 2018
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/22/2018 12:24 AM, Johannes Loher wrote:
 the cryptic acronym NRVO.
It means Named Return Value Optimization. Something I invented :-) https://github.com/dlang/dmd/pull/9117 I shoulda patented it. Then I'd own all the other C++ compilers! HAHHAHHAHAHAHAHAHAAAA!
Dec 22 2018
prev sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Saturday, 22 December 2018 at 08:24:15 UTC, Johannes Loher 
wrote:
 On Friday, 21 December 2018 at 14:43:50 UTC, Boris-Barboris 
 wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker 
 wrote:
 1). I do not like the ability to specify a mutable copy 
 source. Under no circumstance should the code like

 A a;
 A fun()
 {
     return a;      // lowered to return tmp.copyCtor(a)
 }

 void main()
 {
     A b = fun();    // the return value of fun() is moved to 
 the location of b
 }

 be allowed to modify the value of a.
I totally agree. A copy modifying the source is very counter intuitive.
Modifying the source _is_ stupid, however const is transitive so we have no way distinguish modification of the source from modifications through indirections in the source which is useful e.g. incrementing the reference count.
Dec 22 2018
prev sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Friday, 21 December 2018 at 14:43:50 UTC, Boris-Barboris wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor"
1). I do not like the ability to specify a mutable copy source. Under no circumstance should the code like A a; A fun() { return a; // lowered to return tmp.copyCtor(a) } void main() { A b = fun(); // the return value of fun() is moved to the location of b } be allowed to modify the value of a. This is an absolute pain to read\debug, and I would instead like to see a mandatory const\immutable on the source reference. Copy operation should not modify the source, or it should not be called a copy. If we are talking about a typical smart pointer struct (Refcounted), copy still should not modify the source. It is D's transitive const\immutable that is a problem here and it must be explicitly casted away by the developer. Only const also mitigates the combinatorial mess caused by 4 combinations of mutable\immutable copy constructors, since immutable is implicitly converted to const.
As it was stated above, the transitive nature of const and immutable makes it impossible to safely copy objects with indirections. If you do not want to modify the source, then don't modify it from the copy constructor. This can be seen as a feature, not a bug.
 2). "A declaration is a copy constructor declaration if it is a 
 constructor declaration that takes only one non-default 
 parameter by reference that is of the same type as 
 typeof(this), followed by any number of default parameters..."

 If you need other parameters, you are not performing a copy. 
 Copy constructor needs no additional parameters. If the 
 semantics of your domain problem involve parametrized post-copy 
 operations, the code should state that explicitly - by using 
 specialized properly-named methods, that notify the reader 
 about this particularity.
Agree, that was my initial design too, but in C++ you can define any number of default parameters and people coming from that background might have some cases where it is useful for them to have default parameters. Since this is the first iteration of a copy constructor implementation, we should try to stick as much as possible to the C++ design. Of course, in the case of const source we cannot do that since const means something else in D.
 3). Section "Copy constructor usage", I don't understand the 
 difference:

 void main()
 {
     A a;
     A b = a; // copy constructor gets called
     b = a;   // assignment, not initialization
 }
A b = a is an initialization, therefore the copy constructor gets called. b = a is an assignemnt => opAssign gets called
 and

 void main()
 {
     A a;
     a = fun();      // NRVO - no copy constructor call
fun() returns by value so a copy constructor call should be performed when returning, but in this case, because named return value optimization may be applied, it will elide the copy.
     A b; // b is initialized after this semicolon.
     // why is this one not an assignment, but initialization?
     // do we have the difference formally and consistently 
 defined for structs?
     b = gun();      // NRVO cannot be performed, copy 
 constructor is called
 }
Indeed, these examples are a bit confusing, because the copy constructor is called when returning, not on caller site. Even if you would have `A b = gun()`, the value of gun() would be moved, but a copy constructor may be called when returning from gun.
Jan 05
next sibling parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Saturday, 5 January 2019 at 13:34:09 UTC, RazvanN wrote:
 On Friday, 21 December 2018 at 14:43:50 UTC, Boris-Barboris 
 wrote:
 As it was stated above, the transitive nature of const and 
 immutable
 makes it impossible to safely copy objects with indirections. 
 If you do
 not want to modify the source, then don't modify it from the 
 copy constructor.
 This can be seen as a feature, not a bug.
1). I personally do not want such feature, I find it dangerous. 2). That would make sense, if that was ever an ambiguous choice. I cannot think of any case where you need to modify the source outside of move operation, and that has nothing to do with copy constructors. You are giving a choice in the situation where only one, known answer is always right. We even know what's the problem is - our wonderful transitive const, that proves itself inadequate for typical smart pointer copying. Maybe instead of hacking in another poorly-integrated feature, we should fix that first? There were plenty of topics dedicated to head const semantics, why not address them now? It will solve lots of other range-related problems as well. 3). As someone who would like to stick to C++, I think you would say that you would feel right at home with the following semantics: this(ref const typeof(this) rhs) - copy constructor this(ref typeof(this) rhs) - move constructor I'm not a fan of the proposed opMove.
 Agree, that was my initial design too, but in C++ you can 
 define any number of
 default parameters and people coming from that background might 
 have some cases
 where it is useful for them to have default parameters. Since 
 this is the first
 iteration of a copy constructor implementation, we should try 
 to stick as much
 as possible to the C++ design. Of course, in the case of const 
 source we cannot
 do that since const means something else in D.
The key difference between copy\move constructors and other constructors is that they are implicitly inserted by the compiler in certain scenarios. Documentation that describes such constructors should not be littered with alternative exotic semantics that have nothing to do with implicitly inserted function calls. this(ref typeof(this) rhs, int b) is just a constructor and should not be mentioned anywhere in the copy constructor documentation, nor in the DIP.
Jan 05
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 5 January 2019 at 14:03:34 UTC, Boris-Barboris wrote:
 1). I personally do not want such feature, I find it dangerous.
I think that the discussion should transcend feelings and stick to what can be done.
 2). That would make sense, if that was ever an ambiguous 
 choice. I cannot think of any case where you need to modify the 
 source outside of move operation, and that has nothing to do 
 with copy constructors. You are giving a choice in the 
 situation where only one, known answer is always right.
 We even know what's the problem is - our wonderful transitive 
 const, that proves itself inadequate for typical smart pointer 
 copying. Maybe instead of hacking in another poorly-integrated 
 feature, we should fix that first? There were plenty of topics 
 dedicated to head const semantics, why not address them now? It 
 will solve lots of other range-related problems as well.
I think that discussing whether const should be transitive or not is beyond the scope of this DIP.
 3). As someone who would like to stick to C++, I think you 
 would say that you would feel right at home with the following 
 semantics:

 this(ref const typeof(this) rhs) - copy constructor
 this(ref typeof(this) rhs) - move constructor

 I'm not a fan of the proposed opMove.
But the opMove DIP proposes a different syntax: https://github.com/dlang/DIPs/pull/109/files#diff-50c61cb5afd3ffe27ddb9c5279fd9fc4R205
 Agree, that was my initial design too, but in C++ you can 
 define any number of
 default parameters and people coming from that background 
 might have some cases
 where it is useful for them to have default parameters. Since 
 this is the first
 iteration of a copy constructor implementation, we should try 
 to stick as much
 as possible to the C++ design. Of course, in the case of const 
 source we cannot
 do that since const means something else in D.
The key difference between copy\move constructors and other constructors is that they are implicitly inserted by the compiler in certain scenarios. Documentation that describes such constructors should not be littered with alternative exotic semantics that have nothing to do with implicitly inserted function calls. this(ref typeof(this) rhs, int b) is just a constructor and should not be mentioned anywhere in the copy constructor documentation, nor in the DIP.
Since the copy constructor can also be used as a normal constructor (calling it explicitly), then there might be situations where you would need the extra parameters.
Jan 05
parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Saturday, 5 January 2019 at 14:16:41 UTC, RazvanN wrote:
 I think that the discussion should transcend feelings and stick 
 to what can be done.
That feeling is coming from reason I highlighted in my original post. "Can be done" is not enough, "should it be done?" is just as important.
 I think that discussing whether const should be transitive or 
 not is beyond the scope of this DIP.
I think no DIP should ever be viewed in isolation. The is no DIP scope. There is one, unified scope of language evolution. All concurrent DIPs and ideas must be accounted for.
 But the opMove DIP proposes a different syntax: 
 https://github.com/dlang/DIPs/pull/109/files#diff-50c61cb5afd3ffe27ddb9c5279fd9fc4R205
Yes, I meant I'm not a fan of that different syntax. Postblit and opPostMove should be merged into one move constructor call if it's defined IMO.
 Since the copy constructor can also be used as a normal 
 constructor (calling it explicitly), then there might be 
 situations where you would need the extra parameters.
Why would you mentioned it anywhere though? It's already implemented, we have such constructors. What does it have to do with copy constructor, besides the first argument?
Jan 05
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 5 January 2019 at 14:39:06 UTC, Boris-Barboris wrote:

 Why would you mentioned it anywhere though? It's already 
 implemented, we have such constructors. What does it have to do 
 with copy constructor, besides the first argument?
Prior to this DIP, one might have defined: this(ref S a, int b=0) {} This function is called only explicitly, but after this DIP, it will get called whenever a S instance will be copied. If you are against this function being a copy constructor, I can understand that, but C++ is considering it a copy constructor and for this first iteration, we are too.
Jan 05
parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Saturday, 5 January 2019 at 14:44:12 UTC, RazvanN wrote:
 This function is called only explicitly, but after this DIP, it 
 will get called whenever a S instance will be copied. If you 
 are against this function being a copy constructor, I can 
 understand that, but C++ is considering it a copy constructor 
 and for this first iteration, we are too.
Oh... I didn't know C++ went that way, I now understand your reasoning, sorry. You're right, I'm against it, but if that's an expected behavior, it's probably for the best. How do they deal with ambiguity (multiple copy constructors with different argument tuples), just halt with a compiler error?
Jan 05
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 5 January 2019 at 15:00:32 UTC, Boris-Barboris wrote:
 On Saturday, 5 January 2019 at 14:44:12 UTC, RazvanN wrote:
 This function is called only explicitly, but after this DIP, 
 it will get called whenever a S instance will be copied. If 
 you are against this function being a copy constructor, I can 
 understand that, but C++ is considering it a copy constructor 
 and for this first iteration, we are too.
Oh... I didn't know C++ went that way, I now understand your reasoning, sorry. You're right, I'm against it, but if that's an expected behavior, it's probably for the best. How do they deal with ambiguity (multiple copy constructors with different argument tuples), just halt with a compiler error?
Yes.
Jan 05
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 5 January 2019 at 13:34:09 UTC, RazvanN wrote:
 On Friday, 21 December 2018 at 14:43:50 UTC, Boris-Barboris 
 wrote:
 2). "A declaration is a copy constructor declaration if it is 
 a constructor declaration that takes only one non-default 
 parameter by reference that is of the same type as 
 typeof(this), followed by any number of default parameters..."

 If you need other parameters, you are not performing a copy. 
 Copy constructor needs no additional parameters. If the 
 semantics of your domain problem involve parametrized 
 post-copy operations, the code should state that explicitly - 
 by using specialized properly-named methods, that notify the 
 reader about this particularity.
Agree, that was my initial design too, but in C++ you can define any number of default parameters and people coming from that background might have some cases where it is useful for them to have default parameters. Since this is the first iteration of a copy constructor implementation, we should try to stick as much as possible to the C++ design. Of course, in the case of const source we cannot do that since const means something else in D.
This seems like a weak justification to me. There are many things in C++ that are permitted by the language but considered poor practice by the C++ community, and continue to exist only for the sake of backward compatibility. D should not blindly adopt behavior from C++ without considering why that behavior exists in C++, and whether D could do better. I have not been able to find many sources on whether copy constructors with optional parameters are regarded as useful or good practice in the C++ community, but the results I have found are not encouraging. In the C++ Core Guidelines, the section on copy constructors [1] does not even acknowledge the possibility of additional optional parameters. In addition, at least one static analysis tool for C++ considers copy constructors with optional parameters an error [2], because they may be called implicitly in places the programmer did not intend them to be. None of this is conclusive evidence, of course, but at the very least, it indicates that this is an issue on which the C++ community is divided. If there are specific, known benefits to allowing copy constructors with optional parameters in D, then the DIP should articulate those benefits. "C++ does it that way" is not good enough. Otherwise, it may be better to go ahead with only single-parameter copy constructors, and leave the question of copy constructors with optional parameters for a future DIP. [1] https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-ctor [2] https://help.semmle.com/wiki/display/CCPPOBJ/Constructor+with+default+arguments+will+be+used+as+a+copy+constructor
Jan 05
prev sibling next sibling parent reply Johannes Loher <johannes.loher fg4f.de> writes:
In the section "Copy constructor call vs. blitting", the DIP 
explains how copying is handled when no copy constructor is 
defined:

 When a copy constructor is not defined for a struct, 
 initializations are handled by copying the contents from the 
 memory location of the right-hand side expression to the memory 
 location of the left-hand side expression (i.e. "blitting"):

 struct A
 {
     int[] a;
 }

 void main()
 {
     A a = A([7]);
     A b = a;                 // mempcy(&b, &a)
     immutable A c = A([12]);
     immutable A d = c;       // memcpy(&d, &c)
 }
Then later, in the section "Generating copy constructors", the DIP describes under which situations copy constructors are generated implicitly:
 A copy constructor is generated implicitly by the compiler for 
 a struct S if:
 
     S does not define any copy constructors;
     S does not have an overlapping field that defines a copy 
 constructor;
     S defines at least one member that has a copy constructor.
 
 If all of the restrictions above are met, the following copy 
 constructor is generated:
 
 this(ref inout(S) src) inout
 {
     foreach (i, ref inout field; src.tupleof)
         this.tupleof[i] = field;
 }
Those two statements contradict each other. The first one clearly states that whenever no copy constructor is defined, copying is done by blitting (without exception).
Dec 22 2018
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 22 December 2018 at 08:40:21 UTC, Johannes Loher 
wrote:
 Those two statements contradict each other. The first one 
 clearly states that whenever no copy constructor is defined, 
 copying is done by blitting (without exception).
You are right, it's not very well stated, but I thought it would be obvious from the examples. The idea here is that when a struct does not define any copy constructors and the fields of the struct do not define any copy constructors, blitting is employed. If at least one field does define a copy constructor, then the above mentioned copy constructor is generated. Hope this sheds some light.
Jan 05
prev sibling next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 https://github.com/dlang/DIPs/blob/07da1f2cabc8b1bc3ad66034598a133e5ad13356/DIPs/DIP1018.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on January 4, or when I make a post declaring it complete. 
 (This time I'm extending the review period by a few days 
 because of the holidays.)

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of community 
 review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment by the language maintainers.

 Please familiarize yourself with the documentation for the 
 Community Review before participating.

 https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review

 Thanks in advance to all who participate.
Motivation section needs to cover the RC GC algorithm and why the current features is unable to implement the algorithm properly while the introduction of copy constructor allows to implement it. That is the major motivation that can't be over looked. Alex.
Dec 22 2018
prev sibling next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 https://github.com/dlang/DIPs/blob/07da1f2cabc8b1bc3ad66034598a133e5ad13356/DIPs/DIP1018.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on January 4, or when I make a post declaring it complete. 
 (This time I'm extending the review period by a few days 
 because of the holidays.)

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of community 
 review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment by the language maintainers.

 Please familiarize yourself with the documentation for the 
 Community Review before participating.

 https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review

 Thanks in advance to all who participate.
I only realised that there would be a change to move semantics for structs that define a copy constructor at the end. Can one still manually move such structs? I'd like the DIP to go into that.
Dec 22 2018
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 22 December 2018 at 16:40:47 UTC, Atila Neves wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 https://github.com/dlang/DIPs/blob/07da1f2cabc8b1bc3ad66034598a133e5ad13356/DIPs/DIP1018.md

 All review-related feedback on and discussion of the DIP 
 should occur in this thread. The review period will end at 
 11:59 PM ET on January 4, or when I make a post declaring it 
 complete. (This time I'm extending the review period by a few 
 days because of the holidays.)

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of community 
 review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment by the language maintainers.

 Please familiarize yourself with the documentation for the 
 Community Review before participating.

 https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review

 Thanks in advance to all who participate.
I only realised that there would be a change to move semantics for structs that define a copy constructor at the end. Can one still manually move such structs? I'd like the DIP to go into that.
I think that move and copy constructors are orthogonal concepts. I don't see how copy constructors may affect this. At this point, there is no move operator in D and the copy constructor is used only when a copy is made. If you are referring to Shackar Shamesh's DIP, then yes, one can still manually move such structs. When a copy is made => copy constructor ; when a move is made => opMove
Jan 05
parent reply Atila Neves <atila.neves gmail.com> writes:
On Saturday, 5 January 2019 at 13:47:44 UTC, RazvanN wrote:
 On Saturday, 22 December 2018 at 16:40:47 UTC, Atila Neves 
 wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker 
 wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 https://github.com/dlang/DIPs/blob/07da1f2cabc8b1bc3ad66034598a133e5ad13356/DIPs/DIP1018.md

 All review-related feedback on and discussion of the DIP 
 should occur in this thread. The review period will end at 
 11:59 PM ET on January 4, or when I make a post declaring it 
 complete. (This time I'm extending the review period by a few 
 days because of the holidays.)

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of community 
 review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment by the language maintainers.

 Please familiarize yourself with the documentation for the 
 Community Review before participating.

 https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review

 Thanks in advance to all who participate.
I only realised that there would be a change to move semantics for structs that define a copy constructor at the end. Can one still manually move such structs? I'd like the DIP to go into that.
I think that move and copy constructors are orthogonal concepts.
Perhaps, but moving and copying are not.
 I don't see how copy constructors may affect this.
I didn't either until the example in the DIP: ----------- struct C { this(ref C) {} } void fun(C c) {} void main() { C c; fun(c); } ----------- c is moved before the DIP, and copied afterwards due to the existing constructor being considered a copy constructor.
 At this point, there is no move operator in D and the copy 
 constructor is used only when a copy is made. If you are 
 referring to Shackar Shamesh's DIP,
I wasn't referring to opMove, no, but I think adding a `this(C c)` constructor to the example would do it for rvalues?
Jan 09
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Wednesday, 9 January 2019 at 14:25:44 UTC, Atila Neves wrote:

 I didn't either until the example in the DIP:

 -----------
 struct C { this(ref C) {} }
 void fun(C c) {}
 void main() {
     C c;
     fun(c);
 }
 -----------

 c is moved before the DIP, and copied afterwards due to the 
 existing constructor being considered a copy constructor.
C is not moved in this situation. The following code: struct C { this(this) { import std.stdio; writeln("postblit"); } } void fun(C c) {} void main() { C c; fun(c); } prints "postblit". Am I missing something?
 I wasn't referring to opMove, no, but I think adding a `this(C 
 c)` constructor to the example would do it for rvalues?
The copy constructor is called solely on lvalues. `this(C c)` is a simple constructor that needs to be called explicitly.
Jan 09
prev sibling next sibling parent reply Dru <Dru notreal.com> writes:
First I want to say that I hope it gets implemented
Semantic consistency demands it:

B b;
A a = b; //calls this(B) or this(ref B)
A a2 = a; //*should* call this(ref A)


I have a few points:

1) "ref" vs "ref const" dilemma

The user can overload different kinds of copy ctors,
but what is the *default* copy ctor ?
I think the default copy ctor should be "ref const"
- "ref const" is safer and fits most cases
- "ref" has priority over "ref const" so the user can simply 
overload
and his "ref" ctor will be used instead of the default


2) "Generating copy constructors"

Should the user care when a constructor is "generated" if 
semantics are consistent ?
May just say there is *always* a default copy ctor that can be 
overriden by the user.
The implementation of default ctor can change and use memcpy as 
needed.


3) Not very related but maybe also needs a fix:
I noticed that init to rvalue of a different type is weird right 
now
A a1 = b; //calls this(ref B)
A a2 = B(); //does not call this(ref B)
Dec 22 2018
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 22 December 2018 at 23:26:47 UTC, Dru wrote:
 First I want to say that I hope it gets implemented
 Semantic consistency demands it:

 B b;
 A a = b; //calls this(B) or this(ref B)
 A a2 = a; //*should* call this(ref A)
That is indeed the case.
 I have a few points:

 1) "ref" vs "ref const" dilemma

 The user can overload different kinds of copy ctors,
 but what is the *default* copy ctor ?
 I think the default copy ctor should be "ref const"
 - "ref const" is safer and fits most cases
 - "ref" has priority over "ref const" so the user can simply 
 overload
 and his "ref" ctor will be used instead of the default
There is no default copy constructor. You define the copy constructors you need. There is a generated copy constructor which is defined if a struct does not have a copy constructor, but has fields that define one. Currently, the generation strategy is pretty dumb, but I plan on enhancing it with a later DIP, in which copy constructors are generated based on the qualifiers of the fields copy constructors: struct A { this(ref A rhs) immutable {} this(ref A rhs) {} } struct B { this(ref B rhs) immutable {} } struct C { A a; B b; } For C, one can simply generate the following copy constructors: this(ref C rhs) immutable { this.a = rhs.a; this.b = rhs.b; } this(ref C rhs) { this.a = rhs.a; // copy constructor call this.b = rhs.b; // error, no copy ctor } The first one succeeds in type checking, while the second one does not. I think that this is a superior design to the one in the DIP, but Walter thinks that we should keep things simple in the first iteration and add enhancements later.
 2) "Generating copy constructors"

 Should the user care when a constructor is "generated" if 
 semantics are consistent ?
 May just say there is *always* a default copy ctor that can be 
 overriden by the user.
 The implementation of default ctor can change and use memcpy as 
 needed.
The copy constructor is generated, only if there are copy constructors for some fields that need to be called. The idea is that if a struct defines a copy constructor, it cannot be blitted in any circumstances; the copy constructor should always be used.
 3) Not very related but maybe also needs a fix:
 I noticed that init to rvalue of a different type is weird 
 right now
 A a1 = b; //calls this(ref B)
 A a2 = B(); //does not call this(ref B)
It cannot call it, because the constructor receives a reference and you are passing an rvalue. That is not even a copy constructor, but a regular constructor, so if you want the compiler to call it, simply delete the ref.
Jan 05
parent reply Dru <dru notreal.com> writes:
 The copy constructor is generated, only if there are copy 
 constructors for some fields that need to be called. The idea 
 is that if a struct defines a copy constructor, it cannot be 
 blitted in any circumstances; the copy constructor should 
 always be used.
I offer a simpler logic: A "default" copy constructor is always generated, except when the user defines a constructor of the same signature. Effectively the user can override the default.
 It cannot call it, because the constructor receives a reference 
 and you are passing an rvalue. That is not even a copy 
 constructor, but a regular constructor, so if you want the 
 compiler to call it, simply delete the ref.
yes not related to the DIP just wondering why block the option to pass rvalue by ref
Jan 05
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Saturday, 5 January 2019 at 14:54:41 UTC, Dru wrote:
 The copy constructor is generated, only if there are copy 
 constructors for some fields that need to be called. The idea 
 is that if a struct defines a copy constructor, it cannot be 
 blitted in any circumstances; the copy constructor should 
 always be used.
I offer a simpler logic: A "default" copy constructor is always generated, except when the user defines a constructor of the same signature. Effectively the user can override the default.
Why would you need a default copy constructor? If there aren't any copy constructors defined, the compiler will just blit the fields. Generating a single default copy constructor is not enough. Consider: struct A { int a; } fun(immutable A a) {} void main() { immutable A a; fun(a); } If we define a single copy constructor like you suggested, then this will not work because you have immutable to immutable copy. In this situation it is best to leave the copying to the existing mechanism.
 It cannot call it, because the constructor receives a 
 reference and you are passing an rvalue. That is not even a 
 copy constructor, but a regular constructor, so if you want 
 the compiler to call it, simply delete the ref.
yes not related to the DIP just wondering why block the option to pass rvalue by ref
Currently, the only solution to this is to bind the rvalue to an lvalue: (B __tmp = B(); tmp), but this is problematic because assignment has side effects while in the original case a move is performed. It is not an unsolvable problem, but it would lead to unexpected behavior in some cases.
Jan 05
parent reply Dru <dru notreal.com> writes:
 Why would you need a default copy constructor? If there aren't 
 any copy constructors defined, the compiler will just blit the 
 fields. Generating
For the sake of consistency. Imagine if the user explicitly calls or uses the address of the (generated) copy ctor, then a struct change is made and the copy ctor is "no longer needed" because you can blit. The user code that explicitly used the constructor is now broken.
 a single default copy constructor is not enough.
how about: this(ref const T other); immutable this(ref const T other);
Jan 09
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Wednesday, 9 January 2019 at 08:18:58 UTC, Dru wrote:
 Why would you need a default copy constructor? If there aren't 
 any copy constructors defined, the compiler will just blit the 
 fields. Generating
For the sake of consistency. Imagine if the user explicitly calls or uses the address of the (generated) copy ctor, then a struct change is made and the copy ctor is "no longer needed" because you can blit. The user code that explicitly used the constructor is now broken.
Consistency with what? How would you take the address of the copy constructor? &a.__ctor? As you can see, you have to use the infamous `__` to do that so you should probably avoid it. Other than that what other use cases can be made for the generation of a default copy constructor and implicitly breaking most of the code that uses structs to pass by value to functions? If you want to implicitly declare default copy constructors, you have to define all variants: mutable->mutable, const->const, immutable->immutable, shared->shared, all inout permutations etc. just to have backwards compatibility with the code that already uses structs. A horde of copy constructors to support a niche case. On the other hand, the current design is elegant as it does not touch already existent code and it generates copy constructors as they are indeed needed.
 a single default copy constructor is not enough.
how about: this(ref const T other); immutable this(ref const T other);
Jan 09
parent Dru <dru notreal.com> writes:
An argument for your side:
It can be useful to check if a type is "blit able"
to do that we can check if a copy ctor does not exist.
Jan 10
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 [...]
At the risk of sounding noobish, the copy constructor is only being introduce for structs and not classes correct? Alex
Jan 06
parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Sunday, 6 January 2019 at 22:53:41 UTC, 12345swordy wrote:
 On Tuesday, 18 December 2018 at 14:51:39 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1018, "The Copy Constructor":

 [...]
At the risk of sounding noobish, the copy constructor is only being introduce for structs and not classes correct? Alex
Yes.
Jan 07
parent reply Jacob Carlborg <doob me.com> writes:
On 2019-01-07 10:53, RazvanN wrote:
 On Sunday, 6 January 2019 at 22:53:41 UTC, 12345swordy wrote:
 At the risk of sounding noobish, the copy constructor is only being
 introduce for structs and not classes correct?
Yes.
Why? -- /Jacob Carlborg
Jan 07
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Jan 07, 2019 at 10:54:53PM +0100, Jacob Carlborg via Digitalmars-d
wrote:
 On 2019-01-07 10:53, RazvanN wrote:
 On Sunday, 6 January 2019 at 22:53:41 UTC, 12345swordy wrote:
 At the risk of sounding noobish, the copy constructor is only
 being introduce for structs and not classes correct?
Yes.
Why?
https://forum.dlang.org/post/56378A55.20505 erdani.com T -- My program has no bugs! Only undocumented features...
Jan 07
parent Jacob Carlborg <doob me.com> writes:
On 2019-01-07 23:53, H. S. Teoh wrote:

 https://forum.dlang.org/post/56378A55.20505 erdani.com
Would DIP1000 help with this? -- /Jacob Carlborg
Jan 09