Using in as a parameter qualifier

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Oct 22 12:44:47 PDT 2014


On Wednesday, 22 October 2014 at 19:13:58 UTC, Shriramana Sharma 
via Digitalmars-d-learn wrote:
> Hello people. I'm once more looking at D since I participated 
> here a
> bit last year. Since I'm still not 100% sure about committing 
> myself
> to using D i.o. C++ for my work, I'd really like to resurrect 
> this
> thread to clear my lingering doubts (the full thread is at
> http://forum.dlang.org/post/mailman.469.1369978600.13711.digitalmars-d-learn@puremagic.com
> if people need context):
>
> On 6/1/13, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>> The compiler will move an object rather than copy it when it 
>> can. So, for
>> instance, if you pass the function a temporary, it'll move 
>> that temporary
>> rather than copying it. However, if it's called with an 
>> lvalue, odds are
>> that
>> it's going to have to make a copy (though it might be moved if 
>> it were the
>> last time in the caller that the variable was referenced).
>
> I read the Bartosz Milewski article that someone (Ali?) 
> recommended
> once more. What I understood is that D avoids the 
> copy-*constructor*
> when given an rvalue as a function parameter. But the article 
> seems to
> indicate that D will still make a *blit* copy.
>
> However, Jonathan's comment above indicates otherwise (or am I
> misreading?). What is actually meant above by "move an object 
> rather
> than copy"? In C++(11), move semantics seem to mostly involve a 
> swap
> of pointers ponting to the data. Here we are talking about 
> struct
> objects directly containing the data.
>
> Does "move" means that the content is going to be "moved" to a 
> new
> location in memory i.e. copied and then the old memory freed?

Moved means that the memory for the object is blitted from one 
location to another, so no copy is made and no destructors or 
constructors are run. There's never any freeing of memory 
involved, because it involves objects on the stack, not the heap. 
The memory that held the object will get reused at somepoint when 
the stack pointer moves to the appropriate point in the stack for 
that to make sense, but there's no allocation or deallocation 
going on regardless.

> What I'd really like to see D do (please tell me if it does that
> already) is to avoid constructing the struct twice, once at the 
> caller
> site and second time at the callee site when I'm passing an 
> rvalue
> struct as argument. For example:
>
> bezier.di:
> struct Bezier { int p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y ; }
> void draw(Bezier b) ;
> --
> test.d:
> void main () {
>   draw(Bezier(100, 100, 133, 200, 166, 200, 200, 200)) ;
> }
>
> should only ever cause the one Bezier struct object to be 
> constructed
> because the rvalue is not used at the caller site. Does D do 
> that
> already?

That will result in a move operation. No copying will take place. 
And it technically, it may not actually move anything it all and 
just use the object where it's initially constructed. I'm not 
sure what the actual, generated machine code ends up doing in 
that regard. But there's no copying or double-construction.

> And even if what I'm passing to the draw function is an lvalue, 
> say a
> Bezier b which I have declared in the previous line to draw 
> under
> main(), if it is passed in with "in" keyword which implies 
> "const",
> then the function is not going to change the value anyway, so 
> there
> isn't any need to make a copy and so it makes sense if D 
> actually
> directly uses the content of the variable declared under 
> main(). Does
> D do this already too?

const does _not_ mean that a copy doesn't need to be made. It has 
zero effect on that. In fact, if you're passing an lvaue to a 
function that doesn't take its arguments by ref, it's almost a 
guarantee that a copy will be made. The only exception would be 
if the compiler determines that the lvalue in question is never 
used after that call, in which case, it might just move the 
object rather than copy it.

> A further thought: If instead of draw(Bezier), I have 
> Bezier.draw(),
> then the values will be taken from the Bezier object directly 
> whether
> it is an lvalue or rvalue at the calling site, right?

So, you mean if draw was a member function of Bezier, and you did 
something like

Bezier(100, 100, 133, 200, 166, 200, 200, 200).draw()

you want to know whether a copy of the Bezier object would be 
made? The this member of a struct is a ref - in this case ref 
Bezier - so it doesn't make a copy. The object would be 
constructed in place and then be destroyed after it's used 
(though exactly when it would be destroyed if the object were 
created and called in a complex expression, I'm not sure - 
possibly as soon as the function call terminated, possibly when 
the statement completed).

> And extending this, given that UFCS exists in D, draw(Bezier) 
> and
> Bezier.draw() should be equivalent, meaning that if 
> Bezier.draw()
> doesn't make a copy (even a blit) then draw(Bezier) shouldn't
> [assuming of course that it doesn't alter the contents of the 
> object],
> right?

If draw is a free function, then

Bezier(100, 100, 133, 200, 166, 200, 200, 200).draw()

is literally transformed into

draw(Bezier(100, 100, 133, 200, 166, 200, 200, 200))

by the compiler, so the behavior of those two lines is identical. 
And as I said above, that means that a move is made. Because it's 
dealing with a temporary, the compiler knows that the value is 
unique and that it can therefore do a move instead of a copy, so 
it will.

> Sorry if some of my statements above sound presumptuous, but I'm
> really really excited about D, and really really want to get 
> away from
> C++, so please bear with me... Thanks!

I'm not sure why it would sound presumptious if you're asking 
whether you're understanding or guesses about how D works are 
wrong. Questions are certainly welcome. We all want to see D 
succeed.

Here's a related question on SO that might help you as well:

http://stackoverflow.com/questions/6884996/questions-about-postblit-and-move-semantics/6886520#6886520

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list