Re: Safely moving structs in D

2017-01-25 Thread bitwise via Digitalmars-d-learn
On Tuesday, 24 January 2017 at 11:46:47 UTC, Jonathan M Davis 
wrote:
On Monday, January 23, 2017 22:26:58 bitwise via 
Digitalmars-d-learn wrote:

[...]


Moving structs is fine. The postblit constructor is for when 
they're copied. A copy is unnecessary if the original isn't 
around anymore - e.g. passing an rvalue to a function can move 
the value; it doesn't need to copy it. Even passing an lvalue 
doesn't need to result in a copy if the lvalue is not 
referenced at any point after that function call. However, if 
you're going to end up with two distinct copies, then they need 
to actually be copies, and a postblit constructor will be 
called.


[...]


Awesome, thanks - this makes sense.


Re: Safely moving structs in D

2017-01-24 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, January 23, 2017 22:26:58 bitwise via Digitalmars-d-learn wrote:
> Is it ok to memcpy/memmove a struct in D?
>
> Quote from here:
> https://dlang.org/spec/garbage.html
>
> "Do not have pointers in a struct instance that point back to the
> same instance. The trouble with this is if the instance gets
> moved in memory, the pointer will point back to where it came
> from, with likely disastrous results."
>
> This seems to suggests it's ok to move structs around in memory
> without calling their postblit...but if this is the case, why
> does postblit even exist, if it's not strictly guaranteed to be
> called after the struct has been blitted?

Moving structs is fine. The postblit constructor is for when they're copied.
A copy is unnecessary if the original isn't around anymore - e.g. passing an
rvalue to a function can move the value; it doesn't need to copy it. Even
passing an lvalue doesn't need to result in a copy if the lvalue is not
referenced at any point after that function call. However, if you're going
to end up with two distinct copies, then they need to actually be copies,
and a postblit constructor will be called.

Types that would need postblit constructors would include anything doing
reference counting as well as anything that needs to do a deep copy of
something on the heap (though such structs aren't a great idea, since
usually copying is assumed to be cheap, and having the postblit constructor
allocate on the heap isn't exactly cheap). In reality, I don't think that
many structs typically have postblit constructors, but there are definitely
use cases where they're needed.

The bit about structs not pointing to themselves is to make it legal to move
structs in cases where the compiler knows that only one copy is required,
whereas in C++, because pointing to yourself is perfectly legal, the
compiler has to do a lot more copying, and they had to introduce move
constructors to get around the problem.

- Jonathan M Davis



Re: Safely moving structs in D

2017-01-23 Thread bitwise via Digitalmars-d-learn

On Monday, 23 January 2017 at 23:04:45 UTC, Ali Çehreli wrote:

On 01/23/2017 02:58 PM, bitwise wrote:

I'm confused about what the rules would be here.

It would make sense to call the postblit if present, but 
std.Array

currently does not:
https://github.com/dlang/phobos/blob/04cca5c85ddf2be25381fc63c3e941498b17541b/std/container/array.d#L884



Post-blit is for copying though. Moving should not call 
post-blit. You may want to look at the implementation of 
std.algorithm.move to see how it plays with post-blit:


  https://dlang.org/phobos/std_algorithm_mutation.html#.move

Ali


That's a good point.

It didn't click at first, but checking for postblit is done with 
'hasElaborateCopyConstructor(T)'.


I had thought that what memmove was doing would be considered 
"blitting", and hence require a postblit afterwards.


I did look at std.move, but was mistaken about which code path 
was being taken.
It seemed like structs that defined only a postblit would have 
been moved by assignment:


https://github.com/dlang/phobos/blob/366f6e4e66abe96bca9fd69d03042e08f787d040/std/algorithm/mutation.d#L1310

But in actuality, the memcpy branch fires because 
hasElaborateAssign(T) returns true for structs with a postblit - 
which was unexpected. I don't really understand why, but this 
makes things clearer.


  Thanks



Re: Safely moving structs in D

2017-01-23 Thread Ali Çehreli via Digitalmars-d-learn

On 01/23/2017 02:58 PM, bitwise wrote:

I'm confused about what the rules would be here.

It would make sense to call the postblit if present, but std.Array
currently does not:
https://github.com/dlang/phobos/blob/04cca5c85ddf2be25381fc63c3e941498b17541b/std/container/array.d#L884



Post-blit is for copying though. Moving should not call post-blit. You 
may want to look at the implementation of std.algorithm.move to see how 
it plays with post-blit:


  https://dlang.org/phobos/std_algorithm_mutation.html#.move

Ali



Re: Safely moving structs in D

2017-01-23 Thread sarn via Digitalmars-d-learn

On Monday, 23 January 2017 at 22:26:58 UTC, bitwise wrote:

Is it ok to memcpy/memmove a struct in D?

Quote from here:
https://dlang.org/spec/garbage.html

"Do not have pointers in a struct instance that point back to 
the same instance. The trouble with this is if the instance 
gets moved in memory, the pointer will point back to where it 
came from, with likely disastrous results."


This seems to suggests it's ok to move structs around in memory 
without calling their postblit...but if this is the case, why 
does postblit even exist, if it's not strictly guaranteed to be 
called after the struct has been blitted?


You may need the postblit for a *copying* blit.  For example, if 
a struct does reference counting, the postblit will need to 
increment the count for the new copy.  It's a slightly different 
solution to what C++ solves with copy constructors, assignment 
operators, etc.  Compared to C++, the D approach is a bit simpler 
and trades off a little flexibility for more opportunities for 
the compiler to generate efficient code.


Here's the situation in C++, BTW:
http://en.cppreference.com/w/cpp/language/rule_of_three


Re: Safely moving structs in D

2017-01-23 Thread bitwise via Digitalmars-d-learn

I'm confused about what the rules would be here.

It would make sense to call the postblit if present, but 
std.Array currently does not:

https://github.com/dlang/phobos/blob/04cca5c85ddf2be25381fc63c3e941498b17541b/std/container/array.d#L884


Safely moving structs in D

2017-01-23 Thread bitwise via Digitalmars-d-learn

Is it ok to memcpy/memmove a struct in D?

Quote from here:
https://dlang.org/spec/garbage.html

"Do not have pointers in a struct instance that point back to the 
same instance. The trouble with this is if the instance gets 
moved in memory, the pointer will point back to where it came 
from, with likely disastrous results."


This seems to suggests it's ok to move structs around in memory 
without calling their postblit...but if this is the case, why 
does postblit even exist, if it's not strictly guaranteed to be 
called after the struct has been blitted?