Discussion Thread: DIP 1040--Copying, Moving, and Forwarding--Community Review Round 1

Walter Bright newshound2 at digitalmars.com
Sat Mar 20 09:06:34 UTC 2021


On 3/18/2021 12:50 PM, deadalnix wrote:
> So, what do we want to do with move constructors anyways? Can't we just move the 
> struct field by field recursively and be done with it? Yes, and I'd argue there 
> is a problem if this isn't enough for 95% of the cases. Which leads to the two 
> use cases I was able to identify:
>   - Non movable struct. It is important that such a struct doesn't move. For 
> instance, when the struct is some sort of header or a larger data segment. 
> Another example is a struct that represent some kind of guard that needs to see 
> its construction/destruction done in order. This can be achieved by disabling 
> the move constructor, whatever the move constructor is defined as. It is fairly 
> easy to realize such use case, the move constructor simply needs to exist at all.

Ok.

>   - Movable struct that require some form of bookkeeping. For these cases, a 
> postblit would work with one exception: interior pointers.

This bookkeeping was the motivation for #DIP1014:

"For example, D structs also may not use the constructor/destructor to register 
themselves with a global registry that keeps track of all instances in the 
system, e.g. via a linked list. This also severely limits the ability to store 
delegates that reference the struct instance from outside the struct."

https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1014.md

Marking the struct as immovable would resolve this problem, too.

> What I refers as interior pointers are struct containing pointer to elements 
> which are within the struct itself. While this idiom exist, it is vanishingly 
> rare and becoming rarer over time. The main reason for this is that memory has 
> become slower, computation faster, and pointer larger, which in turn lead people 
> to use "relative pointers", namely pointer defined as an offset from this. 
> Unless is is expected that the struct may be more than 4GB in size - which is 
> always the case, then it's all good. The extra addition required is well worth 
> the memory saved (and increase hit rate in the cache that result from it). See 
> https://www.youtube.com/watch?v=G3bpj-4tWVU for instance on how the swift 
> runtime started using such techniques.

I didn't know this. This is good info.


> I'll be blunt, once these techniques are known, I've actually never encountered 
> a case of interior pointers that would not be solved by disabling move 
> altogether. I'm not pretending it doesn't exist, but I've never seen it. It 
> simply doesn't make sense to sacrifice any of the above mentioned requirement 
> for it, even it turns out this is really needed, because, well, this is the edge 
> case of the edge case, and while enabling it might be an option, throwing away 
> thing which are good in the general case for it just doesn't make sense.
> 
> I suspect that even then, making the struct unmovable and then definition custom 
> method to move it manually would do the trick just fine. But just in case, here 
> is what I propose: simply add an intrinsic, such as `void* __pre_move_address()` 
> that can be called in the postblit, returning the address of the premove object. 
> Any object using it would, of course, discard 4/ and not be usable as a value 
> and instead always be passed by reference at the ABI level. This is the least 
> constraining requirement to break, because it impact exclusively performances 
> and never correctness like 1/ or 5/ would. However, considering it is possible 
> to it custom once you disable move, I strongly suspect the bang is not worth the 
> effort.

This is more or less what DIP1014 proposed.


More information about the Digitalmars-d mailing list