| |
|
Timon Gehr 
| On 8/2/25 00:06, Richard (Rikki) Andrew Cattermole wrote:
> On 01/08/2025 10:08 PM, Nick Treleaven wrote:
>> On Sunday, 27 July 2025 at 21:52:15 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>> 2. Moving elements should be in DIP even if implementation doesn't support it. I don't think anything special needs to be done here. My understanding is the compiler should be seeing the VarDeclaration -> VarDeclaration assignment and handle it normally.
>>
>> I think you are asking for something special:
>>
>> ```d
>> T a, b;
>> alias seq = AliasSeq!(a, b);
>> // auto (x, y) = a;
>> auto x = a[0];
>> auto y = a[1];
>> ```
>>
>> `a[0]` and `a[1]` are not moved by the lowered code.
>>
>> Do you have an example where there should be a move?
>
> You are getting to what I was thinking, there is no reason to mention copying or moving. Its defined behavior elsewhere.
>
The _limitations_ section mentions moves because there is no move-unpack.
`auto (x, y) = move(a);` moves `a` into a temporary, copies `a[0]` and `a[1]`, then destroys the temporary:
```d
import std.stdio;
import core.lifetime;
struct S{
this(this){
writeln("S copied");
}
~this(){
writeln("S destroyed");
}
}
struct Tuple(T...) {
T expand;
alias expand this;
this(this){
writeln("Tuple copied");
}
~this(){
writeln("Tuple destroyed");
}
}
void main(){
Tuple!(S, S) t;
auto (a, b) = move(t);
}
```
```
$ dmd -run test.d
S copied
S copied
S destroyed
S destroyed
Tuple destroyed
S destroyed
S destroyed
Tuple destroyed
S destroyed
S destroyed
```
I.e, it copies the two fields into a temporary, then it destroys the temporary.
What it would look like without the limitation:
```
$ dmd -run test.d
S destroyed
S destroyed
Tuple destroyed
S destroyed
S destroyed
Tuple destroyed
S destroyed
S destroyed
```
The pie-in-the-sky ideal output:
```
S destroyed
S destroyed
```
I also noticed that this causes an ICE in the DMD backend atm, will have to fix it before upstreaming the implementation:
```d
import std.stdio;
import core.lifetime;
struct S{
this(ref S){
writeln("S copied");
}
this(S){
writeln("S moved");
}
~this(){
writeln("S destroyed");
}
}
struct Tuple(T...) {
T expand;
alias expand this;
this(ref Tuple rhs){
this.expand=rhs.expand;
writeln("Tuple copied");
}
this(Tuple rhs){
static foreach(i;0..expand.length)
this.expand[i]=move(rhs.expand[i]);
writeln("S moved");
}
~this(){
writeln("Tuple destroyed");
}
}
void main(){
Tuple!(S, S) t;
auto (a, b) = move(t);
}
```
Once this works though it will still have copies in it, as you can verify by annotating the copy constructor of `S` with `@disable`.
|