funky property error with assoc array

Dan dbdavidson at yahoo.com
Thu Nov 15 10:30:03 PST 2012


On Thursday, 15 November 2012 at 17:24:44 UTC, Jonathan M Davis 
wrote:
> On Thursday, November 15, 2012 14:21:41 Dan wrote:
>> I do not see how copy constructors can help. Receiving const(T)
>> or const(T) ref to anything and hoping to copy it is the
>> challenge and doing it from a copy constructor is no easier 
>> than
>> a postblit.
>
> Doing it from a postblit is impossible.

I understand and this makes sense. postblit is not a deep copy, 
it is only what you choose to make it.

> Doing it from a copy constructor _is_
> possible (assuming that they're added to the language - they 
> don't help you
> any until they are).

I question the need for this - at least for structs composed of 
structs, dynamic arrays and associative arrays. Classes are 
another issue.

> The core problem with postblit constructor is that it
> does a shallow copy _before_ entering the postblit constructor. 
> This seems
> great at first, because then you only have to copy stuff in the 
> postblit itself
> which actually needs a deep copy. But it fails completely with 
> const and
> immutable, because it's illegal to alter anything which is 
> const or immutable
> - even by casting them to mutable temporarily to make the 
> change (doing so is
> undefined behavior). So, you can't change _anything_ in a const 
> postblit
> constructor, meaning that you can't make a deep copy of 
> anything.
>

Understood. I don't think the problem with postblit is what it 
does _before_ I do my thing. The problem for this case is it can 
not guarantee what I do *in* my postblit and therefore it does 
not and can not know I'm leaving with no sharing. I don't see 
this as a failure, though. You want a copy, then you need to make 
a copy. Find a way other than postblit. The suggestion is use 
copy constructors instead. I don't see how this will help - but I 
have not found the proposal (do you have a link?).  I have read 
DIP10 which was an early attempt to get at this stuff - but I 
think it did not go far.

> A copy constructor, on the other hand, does not do any copying 
> beforehand. It
> all must still be constructed. The copy constructor then 
> constructs the new
> object with deep copies of the data. This works with const and 
> immutable,
> because it's construction rather than mutation. The postblit 
> constructor fails
> because it requires you to use mutation, which doesn't work 
> with const.
>

A copy ctor does not copy anything beforehand. True. Then the 
idea with this new feature is to leave it to you to copy the 
fields from inside your new copy ctor. But you will no more be 
able to copy them from a copy ctor than you were from a postblit 
because you have a const instance as your source and something 
extra is needed for each field. Now if that something extra is 
more copy constructors all down the line - I think that would 
work but is unnecessary. I think that the real need is a global 
dup or deep copy function. It should be possible without touching 
our structs and I think I have something fairly close when it 
comes to structs, associative arrays, and dynamic arrays.

> So, as nice an idea as it is, the postblit constructor is a 
> failure.

I feel it is not a failure. It is doing its job just fine. The 
natural tendency, especially coming from c++ is to assume const 
values assigned into non-const lvalues should be ok - because we 
are used to deep copy semantics just working. The only problem is 
copy construction (and therefore postblit) is not the right tool 
to copy const instances with reference semantics. I think a 
global dup function would be the right tool and it is doable, 
hopefully with a reasonable performance overhead.

The issue is you want to copy a const(T). Suppose I give you a 
function that works like this (by the way this is working code (I 
use 2.061))

import std.stdio;
import opmix.mix;
struct S {
   char[] c;
}

void foo(ref const(S) s) {
   // I really need a copy here
   auto copy = s.gdup;
   assert(s.c.ptr != copy.c.ptr);
   writeln(copy);
}
void main() {
   S s = {['a','b','c']};
   foo(s);
}

Now if you had this gdup, all your copy ctors would look like 
this:
struct S {
   char[] c;
   S(ref const(S) s) {
      swap(this, s.gdup);
   }
}

But if you had that gdup in the first place, there would be no 
need for copy ctors. Besides, if the compiler could *know* that 
my new copy ctor was really doing a deep copy - why make me write 
it in the first place. Just provide the implementation for me. 
Allowing me to do anything in the copy ctor allows me to 
introduce sharing which is forbidden.

Does this make sense?

Thanks
Dan




More information about the Digitalmars-d-learn mailing list