fieldPostBlit - what is wrong with this and workarounds

Jonathan M Davis jmdavisProg at gmx.com
Fri Nov 1 13:29:45 PDT 2013


On Friday, November 01, 2013 14:28:55 Daniel Davidson wrote:
> On Thursday, 31 October 2013 at 19:39:44 UTC, Jonathan M Davis
> 
> wrote:
> > const and postblit fundamentally don't mix, because for it to
> > work, you have
> > to violate the type system. With postblits, the struct gets
> > memcpied and then
> > the postblit constructor has the chance to mutate the resulting
> > object to make
> > the pieces different that need to be different. However, to do
> > that mutation
> > when the object is const would mean mutating a const object
> > which violates the
> > type system. What we really need is copy constructors, but they
> > haven't been
> > added yet. At one point, Andrei was saying that he and Walter
> > had a solution,
> > but he didn't elaborate on it. I assume that it involved
> > introducing copy
> > constructors, but I don't know, and this issue has not yet been
> > resolved.
> 
> This makes sense, but I think we could have a simpler solution
> that does not involve a copy constructor addition. It seems the
> problem is postblit offers a hole in the system whereby
> developers could change immutable data. Because of that postblit
> and const don't mix. The simple fix would be take the
> implementation of postblit away from the developer. It seems the
> use case for postblit is really only to provide deep copy
> semantics by having developer throw in a bunch of dups where
> desired.

Deep copying is not the only reason to have a postblit. Smart pointers such as 
std.typecons.RefCounted require a postblit (or copy constructor if we had 
those) to do their job. Also, even if all you want is a deep copy, it's 
possible that the member being deep copied was allocated via something like 
malloc, in which case, the compiler couldn't take care of it for you.

> I am now convinced avoiding `const(T) t` as a member is wise
> advice. The suggestion of leaving it non-const and providing a
> const accessor is good - but it won't prevent module code from
> modifying it. I really want to make sure it is not being mutated.
> So I'm now leaning toward this approach:
> 
> struct S {
> const(T) *rc;
> }
> 
> so I won't have the copy/postblit issues. Doesn't this bypass the
> problems with `const(T) t`. The new risk is that somehow that
> member variable is initialized with a stack variable.

If you do that, then rc can be mutated (and so the struct can be mutated), but 
what it points to can't be. So, from the sounds if it, it does what you want. 
Though honestly, I wouldn't worry about the rest of a module mutating your 
member variable just because it has access to it. If you simply name member 
variables differently than the public API (e.g _rc instead of rc) and then 
provide a const property to access the member, then the odds are very low that 
you're going to accidentally access the member directly. And if you can't keep 
track of what's in a single module well enough to avoid this sort of problem, 
then your module is probably too big. But if you're paranoid, you can 
certainly add an extra layer indirection like you're suggesting. I wouldn't 
bother though.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list