[OT] Move semantics in a nutshell

Richard (Rikki) Andrew Cattermole richard at cattermole.co.nz
Sun Nov 9 11:23:35 UTC 2025


On 09/11/2025 12:26 PM, Timon Gehr wrote:
> On 11/8/25 18:55, Richard (Rikki) Andrew Cattermole wrote:
>>> I am not sure what is Kinke's perspective as he has not commented as 
>>> much about the topic.
>>>
>>>
>>> Supporting "destructive moves" implies callee-side destruction is 
>>> more natural (which actually happens to be the traditional convention 
>>> with `extern(D)`). However, this then either requires a bit more 
>>> advanced static analysis than what DMD is currently doing, or 
>>> introducing additional runtime boolean flags and branches to the 
>>> destruction logic (though the flags would not have to pass function 
>>> boundaries).
>>
>> The flags are used for exceptions handling, its not a new thing.
>> Backends are very good at optimizing such flags.
>>
>>> Personally I think adding implicit additional boolean flags and 
>>> branching is a no-go, so the tradeoff revolves around either adding 
>>> non- trivial logic to the type checker in order to attempt to ensure 
>>> that the old values remain inaccessible, or settling on the "husk" 
>>> design.
>>>
>>> Personally, I expect husks to win and invariants to lose in D, at 
>>> least in the near term. While this C++ issue is then not resolved, 
>>> Manu's design does already avoid the "too many reference types" 
>>> problem from C++.
>>
>> Right now only the last copy is promoted to a move,
> 
> Last time I checked, no such promotion happens beyond some very specific 
> special cases. While the DIP that proposed last-use analysis had been 
> accepted, I don't expect it's going to be implemented anytime soon. 
> Unless your DFA helps with that?

It cannot.

1. Its missing value tracking (+ VRP is next up after it goes into a 
release)

2. This alters the AST beyond flagging an AST node. I.e. its ok to flag 
an expression as non-null, but not remove a node.

I suspect the best way to handle this is to ensure that the called 
functions split out the blit/destructor call in such a way that they can 
be removed during optimization with a custom backend pass.

>> so this whole issue really only comes down to manually written moves.
> 
> Well, given there is actually last-use analysis then you can simply 
> check whether manually written moves coincide with last uses. The moves 
> that need to be `@system` are the ones that the type checker is not able 
> to prove `@safe`, like with basically any other feature.

Okay yeah that makes sense.

>> Quite frankly those can be @system and that removes the entire problem 
>> as far as the language is concerned.
>> ...
> 
> Not exactly. Additionally there still needs to be some way to manually 
> elide destructor calls so the language does not accidentally attempt to 
> destroy "unsafe husks".
> 
> Also, it's a bit of a cop out and likely does not match common 
> expectations on ergonomics of move semantics in new languages going 
> forward.
> 
>> Overall I don't understand the point of move constructors, its not 
>> like you can use them to aid ownership transfer systems and as far as 
>> I'm aware they are the only thing that really benefits from it.
>>
> 
> The main utility of move constructors is in supporting internal 
> references. In a husk design, they may also need to be written 
> specifically such as to leave behind a benign husk (e.g., this is the 
> case in C++).

Yeah I get that you need a hook for it. But not how we've tuned them so 
that they are mutually inclusive of copy constructors.



More information about the Digitalmars-d mailing list