fieldPostBlit - what is wrong with this and workarounds

Daniel Davidson nospam at spam.com
Wed Nov 6 06:37:21 PST 2013


On Friday, 1 November 2013 at 20:29:54 UTC, Jonathan M Davis 
wrote:
> On Friday, November 01, 2013 14:28:55 Daniel Davidson wrote:
>> On Thursday, 31 October 2013 at 19:39:44 UTC, Jonathan M Davis

> 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.
>

So, deepCopy is a reason for postblit and I probably common for 
those not wanting shared state. You have mentioned two more uses 
for postblit, ref counting and dealing with something allocated 
with malloc. Honestly I am not sure the impact of the latter. Are 
you referring to `struct T { S *s }` where the s was allocated 
with malloc?  I think you give up on const/immutable when ref 
counting anyway? Regardless, I imagine both of those cases are on 
the less common side and are probably not too troubled by const 
issues. I'm not suggesting getting rid of postblit. Neither am I 
against constructors. It just sounds like adding constructors is 
overkill if support for immutable language generated postblit 
were available. And I think it would be easy to add.

I'm just suggesting add an annotation that marks fields to be 
duped by a language generated postblit. The developer would not 
need to implement the postblit and it would be clear when/where 
sharing occurs. Then the language is still guaranteed immutable 
correct when using the language generated postblit.

>> 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.

Correct - I'm not worried about rc being modified as it is pretty 
easy to control that.

I was under the impression it is pretty easy to 
innocently/unknowingly mutate data. Suppose a member function 
passes that member `t` to any function in any other module. With 
slices and maps, what is really being passed around are pointers. 
Once you start passing them around in a non-const or 
non-immutable context you have objects sharing the same pieces 
data and eventually it could be changed, even though not in your 
module.

> 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.

Not sure I agree because passing non-const instances to functions 
anywhere in the system is now allowed if the member is non-const. 
So it has less to do with the size of your module and more to do 
with where you are passing it. If you are passing it around 
non-const the door is wide open.

> 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

Clearly I am paranoid :-)

But I think it is the case that const(T) and immutable(T) would 
be just fine and your reservations would be gone if the postblit 
were in fact immutable. If this were the case, wouldn't you 
change your stance and recommend const(T) or immutable(T) if in 
fact that is what the expectation is for the developer.

Thanks
Dan


More information about the Digitalmars-d-learn mailing list