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