I've started to try to understand more what move semantics is and how and when
I can make my code benefit from it. I've watched Araq's talk on it and read a
few threads on the forum along with the Destructors page in the docs. But I
don't feel like I've really managed to nail down what's the difference between
a copy and a move. So I have a few cases that I wanted to ask about regarding
objects and seqs. Correct me if I'm saying something wrong in my assumptions
here :-)
**Case 1:** Say we have a purely stack-allocated object:
type
MyObj = object
# only int, floats or other stack-allocated objects here
proc consume(x: sink MyObj) =
# Do something with it
discard
proc ex1() =
var x = MyObj()
var y = x # a move, right? Because x isn't used anymore
# If I had echoed `x` here, then the above line would have been a copy
instead?
proc ex2() =
var x = MyObj()
consume(x) # x is moved into consume right away?
# an echo here would make the above line a copy of x instead?
Run
What exactly is happening in memory on a move compared to copy in this case? Or
are they basically the same in this case (except the move zeros the source)?
**Case 2:** Now let's introduce a object with a seq:
type
MyObj = object
children: seq[MyObj]
proc consume(x: sink MyObj) =
# Do something with it
discard
proc ex3() =
var x = createLargeTree() # just creates a deep tree of nested MyObjs,
the main thing is that it's big in memory
var y = x
proc ex4() =
var x = createLargeTree() # just creates a deep tree of nested MyObjs,
the main thing is that it's big in memory
var y = x # now this is a copy
consume(x) # x get's moved into consume
Run
My question here is what's happening to the seq field in this case when x is
moved. The thing that throws me off is that seqs has value semantics and are
deeply copied on "copy" but it's in fact just a stack-pointer to memory on the
heap. Depending on how seqs in objects are implemented I can see two ways a
move could work:
1. All the MyObj's fields are just copied directly like
y.field = x.field
Run
which would mean that the value semantics of seqs come into play and the entire
tree is copied along with the object.
2. Arc is smart and knows how different fields should be treated. It knows
that it should just copy the pointer of the seq and not the seq itself to avoid
unneccecary copies.
If it's option 2 I think I'm starting to see why move semantics can be more
efficient in some cases. A last question: Arc does sink parameter interference,
right? Do I ever need to annotate my procs with "sink" or can I trust it to
always move when I consume a variable at the end of a proc?
Hopefully my questions are fairly understandable and not too obvious. Thank you
in advance! :-D