www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Move Semantics

reply Alex <sascha.orlov gmail.com> writes:
Another question on move semantics from the cheap seats...

See my code here: http://dpaste.dzfl.pl/995c5af59dd6
There are indeed three questions, all marked in the code, so the 
rest of the text here is maybe redundant... but just in case and 
for summary:

I try to model a inner class of some outer one. Then, as I 
learned from the docu, there is a implicit pointer to the outer 
class from the inner one by ".outer" key word. So far so good.
My outer class has an associative array of the inner objects.
Now, I try to apply a move action to the inner objects between 
two outer objects.

The first (minor) question is:
I have to initialize some dummy inner objects, before I can apply 
the move action. Is this really necessary? It won't be that 
problem I think, if it is so, but it would be nicer, if I could 
just perform the move operation.

The second question is:
Following my code, the inner object I moved does not disappear 
from the array in the source outer object. Why? I tried it 
without, with an empty and with a non empty destructor, the 
result was the same.

And the third, main, question is:
After I moved the inner object to the new outer object, the 
pointer to the outer object remains in the old state, to the 
source outer object. This is not what I expected! Well, yes this 
is some subjective expectation, but shouldn't an implicit pointer 
update itself to not break the logic of what it points to?

The third question has some more meaning in my case: I would like 
to compose some immutable classes, which are inner classes. The 
only mutable value therein should be the pointer to the outer 
class.
I know, I could manage this by some map (+ an array, optionally) 
construct, and I'm on my way to implement this approach. But 
then, I noticed the nested class section and the implicit 
pointers, which are not present in C++, for example, and I wanted 
to try this solution.
Is there maybe an error somewhere in my code?
Sep 29 2015
next sibling parent anonymous <anonymous example.com> writes:
On Tuesday 29 September 2015 16:38, Alex wrote:

 Another question on move semantics from the cheap seats...
 
 See my code here: http://dpaste.dzfl.pl/995c5af59dd6
[...]
 The first (minor) question is:
 I have to initialize some dummy inner objects, before I can apply 
 the move action. Is this really necessary? It won't be that 
 problem I think, if it is so, but it would be nicer, if I could 
 just perform the move operation.
Accessing an non-existing element of an associative array doesn't initialize it. You have to assign to it. I've been slightly annoyed by this, too. I'm not sure what the reasons for the current behavior are. I guess it would slow down accesses (a bit? a lot?).
 The second question is:
 Following my code, the inner object I moved does not disappear 
 from the array in the source outer object. Why? I tried it 
 without, with an empty and with a non empty destructor, the 
 result was the same.
`move` doesn't know what greater structure you're moving from. It just takes two locations. There's no way for it to figure out that the source location is an element of an associative array or whatever.
 And the third, main, question is:
 After I moved the inner object to the new outer object, the 
 pointer to the outer object remains in the old state, to the 
 source outer object. This is not what I expected! Well, yes this 
 is some subjective expectation, but shouldn't an implicit pointer 
 update itself to not break the logic of what it points to?
Your view on the relations of the objects is that the Inner objects in an Outer's _innerarr field are owned by that Outer object. The compiler and `move` have no such notion. Objects of nested classes are not restricted to exist in fields of their .outer objects. All in all, I think you expected more from nested classes and `move` than they provide. An object of a (non-static) nested class just has a pointer to an object of the outer class. All this allows is some shorter syntax. The bond between the two objects isn't any tighter than other pointers. `move` does little more than copying. It avoids postblits and destroys the source if necessary (i.e. reset to .init). It doesn't have any notion of ownership transfer.
Sep 29 2015
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 09/29/2015 07:38 AM, Alex wrote:

 See my code here: http://dpaste.dzfl.pl/995c5af59dd6
 Following my code, the inner object I moved does not disappear from the
 array in the source outer object. Why?
 After I moved the inner object to the new outer object, the pointer to
 the outer object remains in the old state, to the source outer object.
The output of the program is too complicated for me to understand what the expected behavior should be. Going with the text... :) Some notes: - Unlike C++, as classes have reference semantics, normally there should be no need to move class objects around. * Even so, your expectation of the 'outer' pointer being updated is not something move() can decide on its own. Moving an object's parts elsewhere not necessarily require changing the context it operates in. move() cannot know that being a part of a member associative array (AA) constitues changing the 'outer' pointer. move() doesn't even know that the destination location is a part of a memory that is being used by an AA. - When it is needed to transfer an object from one Outer object to another, setting the .outer property seems to work: import std.stdio; class Outer { int i; this (int i) { writefln("Constructing an Outer at %s.", cast(void*)this); this.i = i; } class Inner { void workWith(Outer newOuter) { this.outer = newOuter; } void report() { writefln("I am working with %s. Its i is %s.", cast(void*)this.outer, this.outer.i); } } } void main() { auto o1 = new Outer(1); auto o2 = new Outer(2); auto inner = o1.new Outer.Inner(); inner.report(); inner.workWith(o2); inner.report(); } (Casting a class variable to void* provides the location of the class object.) Prints: Constructing an Outer at 7F136FB81060. Constructing an Outer at 7F136FB81080. I am working with 7F136FB81060. Its i is 1. I am working with 7F136FB81080. Its i is 2. - Unrelated note: Unless there is a convincing reason, I recommend that constructors simply construct objects. Side-effects like objects' registering themselves should not take place in a constructor. I have been bitten by that myself and I have heard the same suggestion from others several times before. Ali
Sep 29 2015
prev sibling parent Alex <sascha.orlov gmail.com> writes:
Thank you very much for the comments.
It is much clearer now. The .outer link is just a shortcut, which 
does not mean I don't have to reset it, where I have to.
So... essentially, my expectation WAS to subjective and I have to 
separate better, what is the part of the model in my head and 
what is expected from the language/compiler.
Sep 29 2015