www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using in as a parameter qualifier

reply Shriramana Sharma <samjnaa gmail.com> writes:
Hello people.

I have a pair type defined as :

struct pair {
  double x,y ;
  this () {}
  this (double x, double y) { this.x =3D x ; this.y =3D y ; }
}

Consider a function that operates on a pair:

double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }

In C++ the function signature would be: double abs2 ( const pair & a )

So I thought const ref pair a would be appropriate in D -- is that right?

How about the "in" qualifier? Does it only replace C++'s const in this
case or does it also guarantee that the object will not be copied
(&/ref) ?

Also: does D not require member initializer lists like in C++? In C++
I would write the this(double,double) above as: pair(double x, double
y):x(x),y(y){} -- since that language is supposed to guarantee that
once we enter the { of the constructor, all sub-objects are
initialized.

Thanks!

--=20
Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0=
=AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0=
=A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4=
=AE=E0=A4=BE
May 30 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/30/2013 10:36 PM, Shriramana Sharma wrote:

 struct pair {
It is more common to start type names with a capital letter: Pair.
    double x,y ;
    this () {}
That is not allowed. In D, every type has the .init property, which is its default value.
    this (double x, double y) { this.x = x ; this.y = y ; }
 }
That is sensible to ensure that both values are provided. Otherwise, the following struct definition is sufficient: struct Pair { double x, y; } void main() { auto p0 = Pair(); auto p1 = Pair(1.5); // only p1.y is 0 auto p2 = Pair(2.5, 3.5); } You can also set the .init value of the whole type: struct Pair { double x = 10.75; double y = 20.25; }
 Consider a function that operates on a pair:

 double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }

 In C++ the function signature would be: double abs2 ( const pair & a )

 So I thought const ref pair a would be appropriate in D -- is that right?
Yes: double abs2(ref const(Pair) a) { /* ... */ }
 How about the "in" qualifier? Does it only replace C++'s const in this
 case or does it also guarantee that the object will not be copied
 (&/ref) ?
'in' is nothing but 'scope const' (scope is not implemented yet): double abs2(in Pair a) { /* ... */ } Of course, pass-by-vale (the other C++ option) is also possible: double abs2(Pair a) { /* ... */ } This one has the added benefit of compiler's automatic moving of the value to the function. You know that 'a' is a copy of the argument so you can safely move it for use later.
 Also: does D not require member initializer lists like in C++? In C++
 I would write the this(double,double) above as: pair(double x, double
 y):x(x),y(y){} -- since that language is supposed to guarantee that
 once we enter the { of the constructor, all sub-objects are
 initialized.
D guarantees that every member is already initialized by their .init value when the constructor is entered (unless the initial value is 'void'). There are optimizations opportunities through flow analysis but the compiler does not apply them yet. Ali
May 30 2013
next sibling parent reply Shriramana Sharma <samjnaa gmail.com> writes:
On Fri, May 31, 2013 at 12:12 PM, Ali =C3=87ehreli <acehreli yahoo.com> wro=
te:
    double x,y ;
    this () {}
That is not allowed. In D, every type has the .init property, which is it=
s
 default value.
Hm can you clarify that a bit? If I actually try it I get: pair.d(14): Error: constructor pair.pair.this default constructor for structs only allowed with disable and no body
 Consider a function that operates on a pair:
 double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }
 In C++ the function signature would be: double abs2 ( const pair & a )
 So I thought const ref pair a would be appropriate in D -- is that right=
?
 Yes:
 double abs2(ref const(Pair) a) { /* ... */ }
But is this the idiomatic D way of doing things? I mean, would one normally prefer in or ref const(T) which somehow seems more awkward than even const T &?
 'in' is nothing but 'scope const' (scope is not implemented yet):
Does that mean "this is const within the current scope"? And does "in" *not* guarantee that the object is *not* copied? I mean, if a parameter input to a function is read-only, it makes optimization sense to not copy it but just automatically provide a reference to it right? So I would expect in to mean const ref -- doesn't it work that way, and if not, why not?
 double abs2(Pair a) { /* ... */ }
 This one has the added benefit of compiler's automatic moving of the valu=
e
 to the function. You know that 'a' is a copy of the argument so you can
 safely move it for use later.
I don't understand; can you please clarify that. I understand that a is a copy of whatever pair is passed to it, so where do I move it and why would I want to use it later? --=20 Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0= =AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0= =A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4= =AE=E0=A4=BE
May 31 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/31/2013 02:40 AM, Shriramana Sharma wrote:

 On Fri, May 31, 2013 at 12:12 PM, Ali Çehreli <acehreli yahoo.com> wrote:
     double x,y ;
     this () {}
That is not allowed. In D, every type has the .init property, which
is its
 default value.
Hm can you clarify that a bit? If I actually try it I get: pair.d(14): Error: constructor pair.pair.this default constructor for structs only allowed with disable and no body
For structs, the default value of an object is required to be known at compile time, which is its default value. To enforce that rule, the default constructor cannot be provided for structs. What the error message is saying is that you can declare it just to disable its use: struct Pair { double x = 10.75; double y = 20.25; // Default constructor disabled disable this(); // Users must use another constructor: this(double x, double y) { this.x = x; this.y = y; } } As you see, you must also provide a proper constructor that is appropriate for that type.
 Consider a function that operates on a pair:
 double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }
 In C++ the function signature would be: double abs2 ( const pair & a )
 So I thought const ref pair a would be appropriate in D -- is that 
right?
 Yes:
 double abs2(ref const(Pair) a) { /* ... */ }
But is this the idiomatic D way of doing things? I mean, would one normally prefer in or ref const(T) which somehow seems more awkward than even const T &?
Although 'in' feels like it would make all the sense for an in-parameter (at least because it conveys our intent to the compiler), Jonathan explained why 'in' is disappointing. I still use 'in' in the examples in many chapters, which needs to be corrected at some point: http://ddili.org/ders/d.en/function_parameters.html I gave a talk at DConf 2013, which included D's move semantics (starting on slide 11): http://dconf.org/talks/cehreli.html Interestingly, that talk is already old :) due to the improvements in dmd 2.063. Here is an adaptation of an example on the dmd 2.063 changelog: import std.stdio; struct S { this(int i) { writeln("1"); } this(int i) const { writeln("2"); } this(int i) immutable { writeln("3"); } this(int i) shared { writeln("4"); } } void main() { auto a = new S; // writes "1" auto b = new const S; // writes "2" auto c = new immutable S; // writes "3" auto d = new shared S; // writes "4" } D's move semantics are explained in the following blog posts by Bartosz Milewski: http://bartoszmilewski.com/2008/10/18/who-ordered-rvalue-references-part-1/ http://bartoszmilewski.com/2008/10/26/who-ordered-rvalue-references-part-2/ http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/ So, I would use 'ref const' only in special cases and only after profiling proves that there would be no performance penalty for doing that. After all, ref is implemented by a pointer and the indirect access to the members of the object through that pointer may be slow depending on the application. That indirection may even cause the CPU access outside of its caches, which is a relatively very slow operation. However, my short tests on this has demonstrated that by-ref is faster with today's dmd even on a contrived program that accesses to random elements of huge arrays. However, :) if you are going to make a copy of the argument anyway, always take a struct by-value. That works with both lvalue and rvalue arguments and in the case of rvalues, you will get the automatic move semantics. My choice is by-value for structs unless there is any reason not to. Also note that by-ref-to-const is an anti-idiom even in C++ even in surprising places. Everybody defines operator= by taking reference to const, which may be slower than taking by-value. This is the idiomatic way of writing operator= in C++: Foo & operator= (Foo that) { this->swap(that); return *this; }
 it makes optimization sense to not copy it but just automatically 
provide a
 reference to it right?
Unless the language makes a guarantee about that we cannot take the address of the parameter and save it. We wouldn't know whether it is a copy or a reference.
 So I would expect in to mean const ref -- doesn't it work that way, 
and if
 not, why not?
Another reason is less surprise because structs have copy semantics by default. Ali
May 31 2013
next sibling parent reply Shriramana Sharma <samjnaa gmail.com> writes:
Thanks to all who explained the various issues. Some more questions:

On Fri, May 31, 2013 at 9:28 PM, Ali =C3=87ehreli <acehreli yahoo.com> wrot=
e:
 What the error message is saying is that you can declare it just to disab=
le
 its use:

 struct Pair {
     double x =3D 10.75;
     double y =3D 20.25;

     // Default constructor disabled
      disable this();

     // Users must use another constructor:
     this(double x, double y) { this.x =3D x; this.y =3D y; }
 }

 As you see, you must also provide a proper constructor that is appropriat=
e
 for that type.
Sorry but I still don't get it -- if a default constructor is disallowed for struct-s by the language itself, why should I have to *tell* the compiler to disable it?
 However, :) if you are going to make a copy of the argument anyway, alway=
s
 take a struct by-value. That works with both lvalue and rvalue arguments =
and
 in the case of rvalues, you will get the automatic move semantics.

 My choice is by-value for structs unless there is any reason not to.
So where is the cut-off point? I mean, by-value means a copy is done every time the function is called right? So how heavy (in terms of sizeof) would a struct have to be to make passing by ref more efficient than passing by value?
 be slower than taking by-value. This is the idiomatic way of writing
 operator=3D in C++:

     Foo & operator=3D (Foo that)
     {
         this->swap(that);
         return *this;
     }
This assumes that Foo defines a swap method. Maybe good for lists and such. ... One sec... if you take an argument by value, it means the copy constructor would be called. So how is this really more efficient than taking const Foo & as an argument? Is it the code savings that would be done by avoiding duplicating the copy-constructor code in operator=3D too?
 it makes optimization sense to not copy it but just automatically provid=
e
 a
 reference to it right?
Unless the language makes a guarantee about that we cannot take the addre=
ss
 of the parameter and save it. We wouldn't know whether it is a copy or a
 reference.
Can you explain? It's not very clear to me.
 Another reason is less surprise because structs have copy semantics by
 default.
Makes me start thinking I should use class rather than struct for my pair even though there is no polymorphism etc required. Then I can just say abs2(const pair). It would automatically be a reference. Would that be inadvisable for any reason? My program would use pairs heavily. Would the heap allocation/deallocation/GC be a burden if I made the pair a class? --=20 Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0= =AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0= =A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4= =AE=E0=A4=BE
May 31 2013
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/31/2013 10:49 AM, Shriramana Sharma wrote:

 struct Pair {
      double x = 10.75;
      double y = 20.25;

      // Default constructor disabled
       disable this();

      // Users must use another constructor:
      this(double x, double y) { this.x = x; this.y = y; }
 }

 As you see, you must also provide a proper constructor that is 
appropriate
 for that type.
Sorry but I still don't get it -- if a default constructor is disallowed for struct-s by the language itself, why should I have to *tell* the compiler to disable it?
Not when you "have to", when you "want to" disable it.
 However, :) if you are going to make a copy of the argument anyway, 
always
 take a struct by-value. That works with both lvalue and rvalue 
arguments and
 in the case of rvalues, you will get the automatic move semantics.

 My choice is by-value for structs unless there is any reason not to.
So where is the cut-off point? I mean, by-value means a copy is done every time the function is called right? So how heavy (in terms of sizeof) would a struct have to be to make passing by ref more efficient than passing by value?
Nobody knows. The cut-off point would move at any direction by the next generation of CPUs and systems.
 be slower than taking by-value. This is the idiomatic way of writing
 operator= in C++:

      Foo & operator= (Foo that)
      {
          this->swap(that);
          return *this;
      }
This assumes that Foo defines a swap method.
This is not a C++ forum, but... :) Yes, it must define a non-throwing swap member function. That function is almost always extremely fast.
 Maybe good for lists and
 such. ... One sec... if you take an argument by value, it means the
 copy constructor would be called.
We are talking about assignment, which happens to be copy+destroy. No problem there.
 So how is this really more efficient
 than taking const Foo & as an argument?
It as efficient as an exception-safe operator=. It is not as efficient as incorrectly written operator=.
 it makes optimization sense to not copy it but just automatically 
provide
 a
 reference to it right?
Unless the language makes a guarantee about that we cannot take the
address
 of the parameter and save it. We wouldn't know whether it is a copy or a
 reference.
Can you explain? It's not very clear to me.
I thought your proposal was "compiler should automatically provide a reference when it makes sense to." I meant: Assume that you wrote such a function where the compiler can play such a trick. You would not be sure whether you can take the address of the parameter and store it for later use, even inside the function, even to print a diagnostic message. The reason is, you wouldn't know whether the parameter was a reference to the argument or a copy of it.
 Another reason is less surprise because structs have copy semantics by
 default.
Makes me start thinking I should use class rather than struct for my pair even though there is no polymorphism etc required. Then I can just say abs2(const pair). It would automatically be a reference. Would that be inadvisable for any reason? My program would use pairs heavily. Would the heap allocation/deallocation/GC be a burden if I made the pair a class?
Sounds like you really have to run some test code to figure out what will work best for you. But in theory, no, your pair is not a class. It is a simple value type. If you will have member functions, classes will be slower unless you mark those member function as 'final'. Also, class variables always bring an indirection because they are reference types. Ali
May 31 2013
prev sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Friday, 31 May 2013 at 17:50:33 UTC, Shriramana Sharma wrote:
 Sorry but I still don't get it -- if a default constructor is
 disallowed for struct-s by the language itself, why should I 
 have to
 *tell* the compiler to disable it?
The compiler always provides a default constructor (maybe not technically) which is used for .init. By requesting the default constructor be disabled, is really saying don't let anyone declare the struct without initializing it. Testing shows that in 2.060 the init property is still usable, which I expected as it is most useful in generic code. But I don't know if that is sticking around, it is kind of like int a = void;
May 31 2013
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, May 31, 2013 23:25:02 Jesse Phillips wrote:
 On Friday, 31 May 2013 at 17:50:33 UTC, Shriramana Sharma wrote:
 Sorry but I still don't get it -- if a default constructor is
 disallowed for struct-s by the language itself, why should I
 have to
 *tell* the compiler to disable it?
The compiler always provides a default constructor (maybe not technically) which is used for .init. By requesting the default constructor be disabled, is really saying don't let anyone declare the struct without initializing it. Testing shows that in 2.060 the init property is still usable, which I expected as it is most useful in generic code. But I don't know if that is sticking around, it is kind of like int a = void;
I believe that a disabled init property is still useable in some type inference stuff (e.g. typeof(type.init) may still work), but if init has been disabled, then you can't use that struct in any situation which requires default initialization. It's not like you get = void in the cases where init is disabled and you need init. Rather, you just can't use that type in that situation. - Jonathan M Davis
May 31 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, May 31, 2013 23:19:57 Shriramana Sharma wrote:
 However, :) if you are going to make a copy of the argument anyway, always
 take a struct by-value. That works with both lvalue and rvalue arguments
 and in the case of rvalues, you will get the automatic move semantics.
 
 My choice is by-value for structs unless there is any reason not to.
So where is the cut-off point? I mean, by-value means a copy is done every time the function is called right?
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).
 So how heavy (in terms of
 sizeof) would a struct have to be to make passing by ref more
 efficient than passing by value?
That would depend on the compiler. You'd have to do tests to see. Certainly, for anything that's small enough to fit in a register, it's likely to be faster to pass by value. But how much beyond that the struct has to grow before it's large enough that passing by reference would be cheaper, I don't know. A lot that the compiler does could affect that. The only way to know for sure is to test it. - Jonathan M Davis
May 31 2013
prev sibling next sibling parent Shriramana Sharma <samjnaa gmail.com> writes:
On Sat, Jun 1, 2013 at 1:13 AM, Jonathan M Davis <jmdavisProg gmx.com> wrot=
e:
 Certainly,
 for anything that's small enough to fit in a register, it's likely to be =
faster
 to pass by value.
So pardon my ignorance, but a pair which only contains two doubles -- it would fit in a CPU register? How about a bezier class/struct which contains 4 pairs i.e. 8 doubles? And that would mean that passing by value is faster 'cause it's cheaper to copy the data to a register and have the processor operate on it directly than to copy the pointer (which lies beneath the reference) and have the indirection and *then* copy (?) the data? (I mean I'm not sure how these things work -- even when you are using a pointer/reference, copying from the memory to CPU register is unavoidable right? C++'s const T & only makes it so that copying from memory-to-memory can be avoided, right? --=20 Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0= =AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0= =A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4= =AE=E0=A4=BE
May 31 2013
prev sibling parent reply Shriramana Sharma via Digitalmars-d-learn writes:
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 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? 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? 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? 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? 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? 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! -- Shriramana Sharma ஶ்ரீரமணஶர்மா श्रीरमणशर्मा
Oct 22 2014
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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 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: - Jonathan M Davis
Oct 22 2014
next sibling parent reply Shriramana Sharma via Digitalmars-d-learn writes:
Hi Jonathan and thanks again for your kind replies.

On 10/23/14, Jonathan M Davis via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:
 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.
Well blitting is copying isn't it? I read your SE answer where you define a move as a blit without the postblit. Hmm. Somehow the name "move" seems to be misleading... To clarify that, is this the same as the C++11 move behaviour or is it subtly different? IIUC in case of a C++ vector, a move would mean that the length and possibly other direct members of the class including the pointer to the heap-allocated managed data would be copied to the target (same as blit I guess) and the managed data itself is not dupped (i.e. postblit is not called) and we call it a move, yeah? But it's actually better called a shallow copy, no? Or is a shallow copy different from a move in any other way?
 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.
But that doesn't seem logical. If the compiler is able to determine that the lvalue in question is not modified in the function at all (either heuristically or by the programmer defining it as "in" or "const") then it should be able to optimize by not even making the move aka shallow copy, no? Of course I understand it doesn't *have* to do an optimization, and that D believes that ideally optimization opportunities should be recognized and acted upon by the compiler and the user should not need to specify places where this is possible (I listened to the Andrei/Walter panel talk where IIUC they were saying this is the ideal behaviour and keywords like "pure" "nothrow" etc shouldn't ideally be needed), but I just want to be sure whether I'm understanding right that there is indeed the possibility in the present case.
 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.
Actually it doesn't even make a move aka shallow copy right? If that's right, then sorta here we are seeing how a ref to a temporary can indeed exist, i.e. implicitly within the member functions. (I'll post separately on that topic.)
 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.
OK so if I read this right, if the function is defined as a free function, then calling it on a temporary will make a shallow copy (and I can't use an explicit ref on the temporary argument), but if it is defined as a member then calling it on a temporary will not even make a shallow copy. Because of UFCS, how I'm *calling* the function will not have an effect on whether the shallow copy is made or not, but how I *defined* it will. Correct?
 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.
That's very nice of you. I only added the advance apology because sometimes some friends of mine have commented that I come across high and mighty in saying "this should be like this and this and not like that" in technical fora where people more knowledgeable than me exist. As Andrei said in his opening address, it's nice to see that one big strength of D is the patient and friendly replies of the D community. :-) -- Shriramana Sharma ஶ்ரீரமணஶர்மா श्रीरमणशर्मा
Oct 22 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Thursday, 23 October 2014 at 05:17:14 UTC, Shriramana Sharma 
via Digitalmars-d-learn wrote:
 Hi Jonathan and thanks again for your kind replies.

 On 10/23/14, Jonathan M Davis via Digitalmars-d-learn
 <digitalmars-d-learn puremagic.com> wrote:
 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.
Well blitting is copying isn't it? I read your SE answer where you define a move as a blit without the postblit. Hmm. Somehow the name "move" seems to be misleading...
I think a clarification of the terms is in order. * Blitting. This is a low-level bitwise copy from one location to another. Depending on the circumstances, it may be between two memory locations, but it can also be from one or more registers into memory, or vice versa, or between registers. Which one it is can not be influenced nor predicted reliable from a D program, but the compiler's optimizer will try to choose the best method (usually registers). * Copying. This is a high-level operation, defined by the programming language specification. For D, it means _blitting_, followed optionally by a call to a postblit method `this(this)` that can be used to make adjustments to the new copy (e.g. duplicating internal buffers, incrementing a reference counter, ...). For C++, both parts are combined in the copy constructor. * Moving. This is again a high-level concept, meaning that an object is transferred to a new location (variable, parameter), and the old location will be invalid afterwards. Semantically, it should always be equivalent to _copying_ the source to the destination, and then destroying the source. It is implemented as _blitting_ from the source to the destination. In D, it is thus equivalent to copying if there is no postblit defined. On a language level, D itself has no concept of moving, except that the specification forbids structs to contain references into themselves, in order to allow the compiler to choose moving over copying. But there is no way for the programmer to force it; the compiler decides at its own discretion.
 To clarify that, is this the same as the C++11 move behaviour 
 or is it
 subtly different? IIUC in case of a C++ vector, a move would 
 mean that
 the length and possibly other direct members of the class 
 including
 the pointer to the heap-allocated managed data would be copied 
 to the
 target (same as blit I guess) and the managed data itself is not
 dupped (i.e. postblit is not called) and we call it a move, 
 yeah?
Yes.
 But
 it's actually better called a shallow copy, no?

 Or is a shallow copy different from a move in any other way?
Using the above terms, it is a shallow _blit_, because there's no copy-constructor or postblit being called. The point is that the compiler only does it if its outcome is semantically equivalent to a (deep) copy immediately followed by a destruction. This is commonly the case when the source cannot be accessed after the move. To take std::vector as an example, doing a shallow copy if the source is still accessible after the copy will result in a semantically different behaviour, because both containers will now point to the same contents.
 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.
But that doesn't seem logical. If the compiler is able to determine that the lvalue in question is not modified in the function at all (either heuristically or by the programmer defining it as "in" or "const") then it should be able to optimize by not even making the move aka shallow copy, no?
In principle, it could, but there is a complication: The function you call in this particular place can also be called from somewhere else, potentially from a different library which the compiler has no control over. Therefore, it needs to provide a fixed and predictable interface to the outside. The optimization you have in mind requires pass-by-value to be turned into pass-by-reference, which would change this interface. However, the compiler could theoretically provide a different implementation of the function in addition, and keep the original one around for when it's needed. But I'd say this is an advanced optimization technique that you surely cannot rely on.
 Of course I understand it doesn't *have* to do an optimization, 
 and
 that D believes that ideally optimization opportunities should 
 be
 recognized and acted upon by the compiler and the user should 
 not need
 to specify places where this is possible (I listened to the
 Andrei/Walter panel talk where IIUC they were saying this is 
 the ideal
 behaviour and keywords like "pure" "nothrow" etc shouldn't 
 ideally be
 needed), but I just want to be sure whether I'm understanding 
 right
 that there is indeed the possibility in the present case.

 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.
Actually it doesn't even make a move aka shallow copy right? If that's right, then sorta here we are seeing how a ref to a temporary can indeed exist, i.e. implicitly within the member functions. (I'll post separately on that topic.)
Yes, but arguably that's a hole in the language that needs to be plugged ;-) It's certainly an inconsistency. The problem is that inside `draw()`, you don't know whether `this` is a reference to a temporary or a longer lived object. It's dangerous if you accidentally return a reference to a temporary (or in many cases, even a stack variable).
 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.
OK so if I read this right, if the function is defined as a free function, then calling it on a temporary will make a shallow copy (and I can't use an explicit ref on the temporary argument), but if it is defined as a member then calling it on a temporary will not even make a shallow copy. Because of UFCS, how I'm *calling* the function will not have an effect on whether the shallow copy is made or not, but how I *defined* it will. Correct?
Exactly.
Oct 23 2014
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Wednesday, 22 October 2014 at 19:44:49 UTC, Jonathan M Davis 
wrote:
 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.
There's an additional restriction: local variables are guaranteed to live until the end of the scope they are declared in, and they will be destroyed in inverse order of declaration. A move can only happen if this guarantee wouldn't be violated. This is the case, for example, if the object doesn't have a destructor. If it does have one, it can still be moved if the call is at the end of the variable's scope, and the relative order of destruction of the other variables is unchanged. (The variable would then be destroyed on return inside the function, in an order depending on its position in the argument list.)
 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).
AFAIK, always at the end of the entire statement, but I don't know about the order.
Oct 23 2014
prev sibling next sibling parent reply Shriramana Sharma <samjnaa gmail.com> writes:
T24gRnJpLCBNYXkgMzEsIDIwMTMgYXQgMTI6MTIgUE0sIEFsaSDDh2VocmVsaSA8YWNlaHJlbGlA
eWFob28uY29tPiB3cm90ZToNCj4gc3RydWN0IFBhaXIgew0KPiAgIGRvdWJsZSB4LCB5Ow0KPiB9
DQo+DQo+IHZvaWQgbWFpbigpDQo+IHsNCj4gICAgIGF1dG8gcDAgPSBQYWlyKCk7DQo+ICAgICBh
dXRvIHAxID0gUGFpcigxLjUpOyAgICAgICAgLy8gb25seSBwMS55IGlzIDANCg0KV291bGRuJ3Qg
cDEueSBhY3R1YWxseSBiZSBOYU4gYW5kIG5vdCAwPw0KDQotLSANClNocmlyYW1hbmEgU2hhcm1h
IOCutuCvjeCusOCvgOCusOCuruCuo+CutuCusOCvjeCuruCuviDgpLbgpY3gpLDgpYDgpLDgpK7g
pKPgpLbgpLDgpY3gpK7gpL4NCg==
May 31 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Shriramana Sharma:

 Wouldn't p1.y actually be NaN and not 0?
Right. You can verify it with a writeln. Bye, bearophile
May 31 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, May 31, 2013 15:10:01 Shriramana Sharma wrote:
 On Fri, May 31, 2013 at 12:12 PM, Ali Çehreli <acehreli yahoo.com> wrote:
 Consider a function that operates on a pair:
 double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }
 In C++ the function signature would be: double abs2 ( const pair & a )
 So I thought const ref pair a would be appropriate in D -- is that right?
Yes: double abs2(ref const(Pair) a) { /* ... */ }
But is this the idiomatic D way of doing things? I mean, would one normally prefer in or ref const(T) which somehow seems more awkward than even const T &?
In D, const ref does not accept rvalues (unlike C++'s const &). So, if you use const ref, odds are that you need to duplicate the function double abs2(ref const(Pair) a) {...} double abs2(const Pair a) { abs2(a); /* calls the const ref overload */ } If a function is templated, you can use auto ref to avoid the duplication double abs2()(auto ref Pair a) {...} or if you want const double abs2()(auto ref const Pair a) {...} auto ref is not currently implemented for non-templated functions, so if you want to use it, you have to templatize the function (the two examples above have empty template parameter lists just to templatize the function). auto ref makes it so that the function will accept both lvalues and rvalues (it generates a function that accepts by ref for lvalues and one which accepts by value for rvalues). I would advise against ever using in. It's an alias for const scope, and scope is not currently fully implemented. scope is intended to disallow escaping from the function. So, with a non-reference type, using scope is pointless. And with a reference type, if/when scope is fully implemented later, you could end up with compilation errors because you _were_ escaping a scope parameter (e.g. by returning it or by assigning it to a static variable). At present, scope is at least partially implemented with delegates, but that's it. So, I'd advise against using scope (and thus in) with anything other than delegates. The primary benefit of using it with delegates is it allows the compiler to avoid allocating a closure when the function is called.
 'in' is nothing but 'scope const' (scope is not implemented yet):
Does that mean "this is const within the current scope"? And does "in" *not* guarantee that the object is *not* copied? I mean, if a parameter input to a function is read-only, it makes optimization sense to not copy it but just automatically provide a reference to it right? So I would expect in to mean const ref -- doesn't it work that way, and if not, why not?
in most definitely does _not_ guarantee that the object is not copied. Quite the opposite. It's an alias for const scope. If you want to avoid the copy, you need to use ref. in meant something slightly different in D1, and it was kept around for D2 but with the differences in the type system between them, it was decided to make it an alias for const scope. Personally, I wish that it was just gotten rid of outright due to the issues with scope and the confusion that it causes when people want to know what in does, but I guess that they wanted to reduce how much code broke when porting from D1 to D2. - Jonathan M Davis
May 31 2013
prev sibling next sibling parent reply Shriramana Sharma <samjnaa gmail.com> writes:
On Fri, May 31, 2013 at 8:55 PM, Jonathan M Davis <jmdavisProg gmx.com> wro=
te:
 In D, const ref does not accept rvalues (unlike C++'s const &).
So what is the syntax that accepts rvalues and yet does not make a copy of the input object? I mean, as Ali says OK profiling is preferable to find out where exactly passing by value is more efficient than passing by const ref, but I'd like to know anyway what is the syntax available for this so at least until I get my D legs, I can continue some of my practices from C++ without much detriment. I just finished reading this link which Ali gave: http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/ but perhaps due to my ignorance I don't get 100% what he is tryring to say. Is it really relevant for what I am asking, like avoiding a copy-constructor in the input of a function which will not modify its input, even if I pass by value? I'm currently working on a project at some priority, and it's currently at a relatively flexible stage so I am thinking of switching it over to D thinking it would make me finish the job quicker, but if I will have to bend my thinking too much around differences between C++ and D and around unfinished language features (scope?) I think I may stick with C++ at least for the present project and maybe use D for future ones. Advice? --=20 Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0= =AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0= =A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4= =AE=E0=A4=BE
May 31 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/31/2013 04:41 PM, Shriramana Sharma wrote:

 On Fri, May 31, 2013 at 8:55 PM, Jonathan M Davis 
<jmdavisProg gmx.com> wrote:
 In D, const ref does not accept rvalues (unlike C++'s const &).
So what is the syntax that accepts rvalues and yet does not make a copy of the input object?
I think there has been some resolution on that but it has not been implemented yet. I have not read all of the thread. Can others give a summary of the following thread please? http://forum.dlang.org/thread/km3k8v$80p$1 digitalmars.com
 I mean, as Ali says OK profiling is
 preferable to find out where exactly passing by value is more
 efficient than passing by const ref, but I'd like to know anyway what
 is the syntax available for this
That syntax is not available yet. Currently you can take by 'ref const' that does not accept rvalues, or take by value that works for both. Of course there is also function overloading: import std.stdio; struct S { int[100] big; } void foo(ref const(S) s) { writeln("lvalue arg passed by ref"); } void foo(S s) { writeln("either lvalue arg has been copied or rvalue arg has been moved"); } void main() { auto s = S(); foo(s); foo(S()); } However, even the lvalue goes to the by-copy overload of foo: either lvalue arg has been copied or rvalue arg has been moved either lvalue arg has been copied or rvalue arg has been moved Is that by-design? The lvalue s goes to the by-ref overload only if the variable is const to begin with: auto s = const(S)(); Now the output is this: lvalue arg passed by ref either lvalue arg has been copied or rvalue arg has been moved Is that how the overload resolution rules work? Have I asked this already? Why don't I remember? :) Maybe the programmer should not have such large structs anyway. It is always an option to use a slice instead of that fixed-length array.
 I just finished reading this link which Ali gave:
 
http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/
 but perhaps due to my ignorance I don't get 100% what he is tryring to
 say.
That article is about how moving objects is a fundamental operation of D. C++ has three popular basic operations: construction, copy, and assignment. C++11 brings another one: move. Move has been a fundamental struct operation in D for a long time now.
 Is it really relevant for what I am asking, like avoiding a
 copy-constructor in the input of a function which will not modify its
 input, even if I pass by value?
No, not directly relevant but structs object are supposed to be values without identities. The compiler can move them around freely. Maybe that is a better way of looking at the problem. For example, there is not a concept of a copy constructor. The compiler bit-copies and then provides a chance to make corrections. That is different from C++.
 unfinished language features (scope?)
'scope' is not essential at all, but you are right: There may be other issues down the road.
 I think I may stick with C++ at least for the present project and 
maybe use
 D for future ones. Advice?
I will let you and others answer that question. Ali
May 31 2013
prev sibling parent reply Shriramana Sharma <samjnaa gmail.com> writes:
On Sat, Jun 1, 2013 at 5:11 AM, Shriramana Sharma <samjnaa gmail.com> wrote=
:
 So what is the syntax that accepts rvalues and yet does not make a
 copy of the input object? I mean, as Ali says OK profiling is
 preferable to find out where exactly passing by value is more
 efficient than passing by const ref, but I'd like to know anyway what
 is the syntax available for this so at least until I get my D legs, I
 can continue some of my practices from C++ without much detriment.
And again, sorry if I'm being dumb, but is the proposed inout syntax intended to fix this problem or some other problem? http://d.puremagic.com/issues/show_bug.cgi?id=3D3748 is marked as resolved fixed from back in 2011, but if so why did DConf *this year* have a talk on this issue?! --=20 Shriramana Sharma =E0=AE=B6=E0=AF=8D=E0=AE=B0=E0=AF=80=E0=AE=B0=E0=AE=AE=E0= =AE=A3=E0=AE=B6=E0=AE=B0=E0=AF=8D=E0=AE=AE=E0=AE=BE =E0=A4=B6=E0=A5=8D=E0= =A4=B0=E0=A5=80=E0=A4=B0=E0=A4=AE=E0=A4=A3=E0=A4=B6=E0=A4=B0=E0=A5=8D=E0=A4= =AE=E0=A4=BE
May 31 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/31/2013 04:45 PM, Shriramana Sharma wrote:

 And again, sorry if I'm being dumb, but is the proposed inout syntax
 intended to fix this problem or some other problem?
Think of 'inout' as a placeholder for one of the following three: - const - immutable - (no const, nor immutable) inout is deduced at call time and all of the inouts inside a function and even the return type become the qualifier of the argument: inout(int)[] firstHalf(inout(int)[] a) { return a[0..$/2]; } void main() { int[] m; const(int)[] c; immutable(int)[] i; assert(is (typeof(firstHalf(m)) == int[])); assert(is (typeof(firstHalf(c)) == const(int)[])); assert(is (typeof(firstHalf(i)) == immutable(int)[])); } That is a very handy feature for exactly situations like the above.
 why did DConf *this year* have a talk on this issue?!
The previous DConf was in 2007. It will be a yearly event from now on. Ali
May 31 2013
parent Shriramana Sharma <samjnaa gmail.com> writes:
VGhhbmtzIEpvbmF0aGFuIGFuZCBBbGkgZm9yIGFsbCB0aG9zZSBjbGFyaWZpY2F0aW9ucy4NCg0K
LS0gDQpTaHJpcmFtYW5hIFNoYXJtYSDgrrbgr43grrDgr4DgrrDgrq7grqPgrrbgrrDgr43grq7g
rr4g4KS24KWN4KSw4KWA4KSw4KSu4KSj4KS24KSw4KWN4KSu4KS+DQo=
May 31 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Saturday, June 01, 2013 05:11:44 Shriramana Sharma wrote:
 On Fri, May 31, 2013 at 8:55 PM, Jonathan M Davis <jmdavisProg gmx.com> 
wrote:
 In D, const ref does not accept rvalues (unlike C++'s const &).
So what is the syntax that accepts rvalues and yet does not make a copy of the input object?
If you have a templated function, you can use auto ref auto foo(T)(auto ref T var) {..} or if you don't want to templatize the type but just the function: auto foo()(auto ref T var) {...} For non-templated functions, there currently is no solution. You're forced to duplicate the function. Various options are under discussion, and it's likely that auto ref will be used but with slightly different semantics (auto ref on templated functions actually results in two functions - one with ref and one without - and that won't work with non-templated functions). But that hasn't been agreed upon yet. We _will_ have a solution, but it's a hot topic that's still under debate. For various technical reasons, we won't go the C++ route of having const ref accept rvalues (which is usually what people suggest), but we will have a solution relatively soon as there's a fair bit of pressure to resolve the problem. - Jonathan M Davis
May 31 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Saturday, June 01, 2013 04:39:07 Shriramana Sharma wrote:
 On Sat, Jun 1, 2013 at 1:13 AM, Jonathan M Davis <jmdavisProg gmx.com> 
wrote:
 Certainly,
 for anything that's small enough to fit in a register, it's likely to be
 faster to pass by value.
So pardon my ignorance, but a pair which only contains two doubles -- it would fit in a CPU register? How about a bezier class/struct which contains 4 pairs i.e. 8 doubles?
I really don't know. I don't generally deal with anything at the register level. Normally, what you do is you just pass by value unless you know that the struct is huge, and then you just worry about whether passing by value or by reference if profiling makes it clear that passing by value is a performance hit. But it seems to me that in general, worrying about whether something with a few ints or floats in it is going to be able to be passed in a register or not isn't particularly productive unless you've already found it to be a performance problem or know that you're in an environment where it really matters (in which case, you probably know enough about registers to be far better informed about what is and isn't efficient).
 And that would mean that passing by value is faster 'cause it's
 cheaper to copy the data to a register and have the processor operate
 on it directly than to copy the pointer (which lies beneath the
 reference) and have the indirection and *then* copy (?) the data? (I
 mean I'm not sure how these things work -- even when you are using a
 pointer/reference, copying from the memory to CPU register is
 unavoidable right? C++'s const T & only makes it so that copying from
 memory-to-memory can be avoided, right?
Why would you be copying the data if it was a pointer that was passed? If you pass by ref or by pointer, then only a pointer to the data is copied. Member variables may be copid into registers when operated on, but only the pieces that you operated on would end up being copied into registers, and only then if what you're doing requires a register. There's plenty of stuff that just gets passed around on the stack without any operations being done on them besides copying or moving them. It all depends on what's being done with them. But it's been too long since I studied assembly for me to be able to go into all of the details with registers and the like. - Jonathan M Davis
May 31 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Saturday, June 01, 2013 05:15:22 Shriramana Sharma wrote:
 On Sat, Jun 1, 2013 at 5:11 AM, Shriramana Sharma <samjnaa gmail.com> wrote:
 So what is the syntax that accepts rvalues and yet does not make a
 copy of the input object? I mean, as Ali says OK profiling is
 preferable to find out where exactly passing by value is more
 efficient than passing by const ref, but I'd like to know anyway what
 is the syntax available for this so at least until I get my D legs, I
 can continue some of my practices from C++ without much detriment.
And again, sorry if I'm being dumb, but is the proposed inout syntax intended to fix this problem or some other problem? http://d.puremagic.com/issues/show_bug.cgi?id=3748 is marked as resolved fixed from back in 2011, but if so why did DConf *this year* have a talk on this issue?!
inout is completely unrelated. It has to do with having a function which accepts mutable, const, and immutable and returns the same level mutability without having to duplicate your function. You don't want to have to have something like int[] foo(int[] bar) { ... do something return bar[i .. j]; } const(int)[] foo(const(int)[] bar) { ... do something return bar[i .. j]; } immutable(int)[] foo(immutable(int)[] bar) { ... do something return bar[i .. j]; } Without inout, you're forced to do this kind of code duplication when you want to accept multiple types of mutability and return the same mutability. You could just accept const, but then you'd have to return const rather than the original type which could also have been mutable or immutable. const(int)[] foo(const(int)[] bar) { ... do something return bar[i .. j]; } inout solves that problem: inout(int)[] foo(inout(int)[] bar) { ... do something return bar[i .. j]; } You only have to write the function once, and it works with all 3 levels of mutability. - Jonathan M Davis
May 31 2013