opMove DIP interaction with this(this) deprecation

Shachar Shemesh shachar at weka.io
Thu Apr 5 17:28:12 UTC 2018


TL;DR

The opMove DIP proposal (PR 109) is assuming a world where D first 
copies data and then calls user functions to correct it (if applicable). 
With the suggested this(this) deprecation, this is no longer the case.

Links

DIP PR: https://github.com/dlang/DIPs/pull/109

this(this) deprecation announcement: 
https://forum.dlang.org/thread/p9p64v$ue6$1@digitalmars.com


Introduction

About three weeks ago I submitted a proposed DIP to add an optional 
"opMove" to structs. This operator would be called after the compiler 
(or standard library) do an implicit move of a struct, to allow it to 
update both internal and external references.

Andrei's announcement, from 4 days ago, about wishing to deprecate 
this(this), changes that. Personally, I feel the problems are not so 
much actual weakness in the proposed DIP, and more to do with language 
consistency.

The Problems Exposed by this(this)

The main problems relevant to this(this) are:

1. Const/immutable/shared objects being copied result in rather twisted 
logic of what may or may not be done.
2. If struct A @disable this(this), then any struct that has A as a 
member becomes uncopyable. Unlike C++, this is not overrideable by 
anything the containing struct might do.

I feel that problem #1 is, actually, not as serious for move as it is 
for copy. Unlike copy, for move the object being copied has no compiler 
maintained external references. We can relax the rules quite a bit 
during a point in time where noone is referencing data (otherwise, we 
wouldn't be able to initialize immutable objects).

Problem #2 is still relevant, and continues to be relevant for the move 
case.

With that in mind, the main problem I find with my proposed DIP is that, 
if we switch from post blit to copy overriding, we should equally switch 
from post-move to move overriding. The opMove suggestion relies on a 
certain D idiosyncrasy that we are now trying to deprecate.

This, I believe, is the main issue facing us. I believe my DIP proposes 
an adequate solution to problem #1, and I believe we can work around 
problem #2 (or just live with it) without straying too much from the 
current layout.

One Proposed Solution

One way to fix this is to change the DIP according to the following 
guidelines:

1. Make opMove solely responsible for moving the data (move constructor 
like).
2. If neither the struct nor any of its members define a custom opMove, 
the struct may be copied using memcpy (and that's what the implicit 
opMove does).
3. If the struct does not define a custom opMove, but one of its members 
does, then the compiler defines an implicit opMove that memcpys what can 
be memcpy, and calls opMove on what can't.

There are several disadvantages for this road map compared to the 
current proposal:

1. A new implicit member is added to structs. This is poses a much 
greater backward compatibility change compared to the current proposal, 
as it affects introspection constructs such as __traits(allMembers).

2. This new member has non-trivial implementation. This is a potential 
problem in case you want to override it but keep much of the original 
implementation.

My Proposed Solution

My proposed solution is this:

1. Keep the current DIP as is with one change: rename opMove to opPostMove.

2. Since any solution to this(this) deprecation is likely going to 
include fairly major backward compatibility breakage, include the 
transition to opMove, as defined above, as part of the inevitable DIP 
that will resolve this(this). This way we'll be facing one concentrated 
painful transition instead of two.

I am interesting in hearing the community's thoughts on this.

Thank you,
Shachar


More information about the Digitalmars-d mailing list