[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