Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 21:00:46 UTC, Adam D. Ruppe wrote: On Thursday, 25 October 2018 at 19:56:18 UTC, Stanislav Blinov wrote: The current behavior of the compiler is quite the opposite of those "same as" above. Yeah, I guess I am maybe selectively reading the spec in light of the implementation... but I think the examples are just sloppy. Or maybe we have a buggy implementation but idk which is more useful. I still hold my believe that if opAssign is defined then that should be used. In my humble opinion, the current way might/could be faster, but it's not correct.
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 19:56:18 UTC, Stanislav Blinov wrote: The current behavior of the compiler is quite the opposite of those "same as" above. Yeah, I guess I am maybe selectively reading the spec in light of the implementation... but I think the examples are just sloppy. Or maybe we have a buggy implementation but idk which is more useful.
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 13:22:36 UTC, Eduard Staniloiu wrote: The spec doesn't exactly say it uses memset, but it does imply it: https://dlang.org/spec/arrays.html#array-copying talking about "aggressive parallel code optimizations than possible with the serial semantics of C" and "copying" rather than "assigned" etc. but indeed postblit lets this work. You are right. Thank you! I guess I never read/understood it like this. I expected it to use opAssign as that is what's the most natural and intuitive decision for me. I take it that this is the expected behaviour, then. I don't think interpreting the spec like that is correct. It says "...it means that the *contents* of the array are the target of the *assignment*...", and further, in the examples: s[1..2] = t[0..1]; // same as s[1] = t[0] s[0..2] = t[1..3]; // same as s[0] = t[1], s[1] = t[2] The current behavior of the compiler is quite the opposite of those "same as" above. Consider: struct S { @disable this(this); // can't implicitly copy, i.e. pass lvalue to a function void opAssign(ref S rhs) { /* ... */ } // but can explicitly copy } void main() { S x, y; x = y; // works S[10] a; a[0 .. 3] = y; // doesn't compile, i.e. NOT "same as a[0] = y, a[1] = y, a[2] = y" a[0 .. 3] = a[3 .. 6]; // doesn't compile either, i.e. NOT "same as a[0] = a[3], a[1] = a[4], a[2] = a[5]" } I've filed an issue about this around a month ago: https://issues.dlang.org/show_bug.cgi?id=19274
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 12:55:38 UTC, Adam D. Ruppe wrote: On Thursday, 25 October 2018 at 12:25:37 UTC, Eduard Staniloiu wrote: IMHO, this is a bug. The code should lower to calls to opAssing for types that define opAssign. The spec doesn't exactly say it uses memset, but it does imply it: https://dlang.org/spec/arrays.html#array-copying talking about "aggressive parallel code optimizations than possible with the serial semantics of C" and "copying" rather than "assigned" etc. but indeed postblit lets this work. You are right. Thank you! I guess I never read/understood it like this. I expected it to use opAssign as that is what's the most natural and intuitive decision for me. I take it that this is the expected behaviour, then.
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 13:01:06 UTC, Eduard Staniloiu wrote: On Thursday, 25 October 2018 at 12:38:44 UTC, Paul Backus wrote: On Thursday, 25 October 2018 at 12:25:37 UTC, Eduard Staniloiu wrote: As I wrote in the comments above, I was expecting `a[] = b[]` to iterate the slices and assign the elements of b into a. What really happens is a memcpy: as you can see from godblot [0], this gets lowered to a call to `_d_arraycopy`, in druntime. In D, when you assign one aggregate to another, opAssign is only called for the aggregate, not for any of its elements. However, postblit constructors are called for both. Example: https://run.dlang.io/is/XfDaWw Can you, please, give me a link to where it says this in the specs? Based on the example, I would expect that the code gets lowered to some version of `_d_arrayassign` [0]. I still think that this is problematic, as it's unexpected to the user: you're expecting the assignment operator to be called, not the postblit. I know that the compiler can and will create an opAssign if a postblit or dtor is defined, as you can write the assignment as a this._dtor; blit rhs into this. This being said, I think that if the user took the time to define opAssign, it should be called, because he might want to do something extra when an assignment occurs: an ex. having different logs "creating new obj" vs "changing existing obj". Your example will work as expected if you change the opAssign to a postblit constructor: https://run.dlang.io/is/HBbGO2 Accidentally sent to early. One extra reason as to why, imho, this implicit call to the postblit is evil, is that a lot of code will probably break when we'll transition to the CopyConstructor. See RazvanN's PR [0]. This is actually how I stumbled upon this, as I am using his branch with my repo. [0] - https://github.com/dlang/dmd/pull/8688
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 12:38:44 UTC, Paul Backus wrote: On Thursday, 25 October 2018 at 12:25:37 UTC, Eduard Staniloiu wrote: As I wrote in the comments above, I was expecting `a[] = b[]` to iterate the slices and assign the elements of b into a. What really happens is a memcpy: as you can see from godblot [0], this gets lowered to a call to `_d_arraycopy`, in druntime. In D, when you assign one aggregate to another, opAssign is only called for the aggregate, not for any of its elements. However, postblit constructors are called for both. Example: https://run.dlang.io/is/XfDaWw Can you, please, give me a link to where it says this in the specs? Based on the example, I would expect that the code gets lowered to some version of `_d_arrayassign` [0]. I still think that this is problematic, as it's unexpected to the user: you're expecting the assignment operator to be called, not the postblit. I know that the compiler can and will create an opAssign if a postblit or dtor is defined, as you can write the assignment as a this._dtor; blit rhs into this. This being said, I think that if the user took the time to define opAssign, it should be called, because he might want to do something extra when an assignment occurs: an ex. having different logs "creating new obj" vs "changing existing obj". Your example will work as expected if you change the opAssign to a postblit constructor: https://run.dlang.io/is/HBbGO2
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 12:25:37 UTC, Eduard Staniloiu wrote: IMHO, this is a bug. The code should lower to calls to opAssing for types that define opAssign. The spec doesn't exactly say it uses memset, but it does imply it: https://dlang.org/spec/arrays.html#array-copying talking about "aggressive parallel code optimizations than possible with the serial semantics of C" and "copying" rather than "assigned" etc. but indeed postblit lets this work.
Re: Built-in array opSliceAssign
On Thursday, 25 October 2018 at 12:25:37 UTC, Eduard Staniloiu wrote: As I wrote in the comments above, I was expecting `a[] = b[]` to iterate the slices and assign the elements of b into a. What really happens is a memcpy: as you can see from godblot [0], this gets lowered to a call to `_d_arraycopy`, in druntime. In D, when you assign one aggregate to another, opAssign is only called for the aggregate, not for any of its elements. However, postblit constructors are called for both. Example: https://run.dlang.io/is/XfDaWw Your example will work as expected if you change the opAssign to a postblit constructor: https://run.dlang.io/is/HBbGO2