digitalmars.D.learn - Using in as a parameter qualifier
- Shriramana Sharma (25/25) May 30 2013 Hello people.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (34/51) May 30 2013 That is not allowed. In D, every type has the .init property, which is
- Shriramana Sharma (25/40) May 31 2013 s
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (83/106) May 31 2013 For structs, the default value of an object is required to be known at
- Shriramana Sharma (34/65) May 31 2013 Thanks to all who explained the various issues. Some more questions:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (30/85) May 31 2013 Not when you "have to", when you "want to" disable it.
- Jesse Phillips (10/14) May 31 2013 The compiler always provides a default constructor (maybe not
- Jonathan M Davis (8/25) May 31 2013 I believe that a disabled init property is still useable in some type
- Jonathan M Davis (13/24) May 31 2013 The compiler will move an object rather than copy it when it can. So, fo...
- Shriramana Sharma (19/22) May 31 2013 faster
- Shriramana Sharma via Digitalmars-d-learn (53/59) Oct 22 2014 Hello people. I'm once more looking at D since I participated here a
- Jonathan M Davis (49/136) Oct 22 2014 Moved means that the memory for the object is blitted from one
- Shriramana Sharma via Digitalmars-d-learn (47/74) Oct 22 2014 Hi Jonathan and thanks again for your kind replies.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (57/150) Oct 23 2014 I think a clarification of the terms is in order.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (14/28) Oct 23 2014 There's an additional restriction: local variables are guaranteed
- Shriramana Sharma (7/7) May 31 2013 T24gRnJpLCBNYXkgMzEsIDIwMTMgYXQgMTI6MTIgUE0sIEFsaSDDh2VocmVsaSA8YWNlaHJl...
- bearophile (4/5) May 31 2013 Right. You can verify it with a writeln.
- Jonathan M Davis (34/54) May 31 2013 In D, const ref does not accept rvalues (unlike C++'s const &). So, if y...
- Shriramana Sharma (26/27) May 31 2013 So what is the syntax that accepts rvalues and yet does not make a
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (58/76) May 31 2013 I think there has been some resolution on that but it has not been
- Shriramana Sharma (12/18) May 31 2013 And again, sorry if I'm being dumb, but is the proposed inout syntax
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (23/26) May 31 2013 Think of 'inout' as a placeholder for one of the following three:
- Shriramana Sharma (3/3) May 31 2013 VGhhbmtzIEpvbmF0aGFuIGFuZCBBbGkgZm9yIGFsbCB0aG9zZSBjbGFyaWZpY2F0aW9ucy4N...
- Jonathan M Davis (17/22) May 31 2013 If you have a templated function, you can use auto ref
- Jonathan M Davis (22/38) May 31 2013 I really don't know. I don't generally deal with anything at the registe...
- Jonathan M Davis (38/51) May 31 2013 inout is completely unrelated. It has to do with having a function which...
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
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
On Fri, May 31, 2013 at 12:12 PM, Ali =C3=87ehreli <acehreli yahoo.com> wro= te:sdouble x,y ; this () {}That is not allowed. In D, every type has the .init property, which is it=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=eto 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
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:is itsdouble x,y ; this () {}That is not allowed. In D, every type has the .init property, whichFor 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.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 bodyright?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 thatAlthough '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; }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 &?it makes optimization sense to not copy it but just automaticallyprovide areference 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 ifnot, why not?Another reason is less surprise because structs have copy semantics by default. Ali
May 31 2013
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=leits 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=efor 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=stake a struct by-value. That works with both lvalue and rvalue arguments =andin 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?eit makes optimization sense to not copy it but just automatically provid=ssa reference to it right?Unless the language makes a guarantee about that we cannot take the addre=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
On 05/31/2013 10:49 AM, Shriramana Sharma wrote:appropriatestruct 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 isNot when you "have to", when you "want to" disable it.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?alwaysHowever, :) if you are going to make a copy of the argument anyway,arguments andtake a struct by-value. That works with both lvalue and rvalueNobody knows. The cut-off point would move at any direction by the next generation of CPUs and systems.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?This is not a C++ forum, but... :) Yes, it must define a non-throwing swap member function. That function is almost always extremely fast.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.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=.provideit makes optimization sense to not copy it but just automaticallyaddressa reference to it right?Unless the language makes a guarantee about that we cannot take theI 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.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.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. AliAnother 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?
May 31 2013
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
On Friday, May 31, 2013 23:25:02 Jesse Phillips wrote:On Friday, 31 May 2013 at 17:50:33 UTC, Shriramana Sharma wrote: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 DavisSorry 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
On Friday, May 31, 2013 23:19:57 Shriramana Sharma 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).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?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
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 =fasterto 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
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
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: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.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?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
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
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: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.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?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.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.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.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).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.)Exactly.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?
Oct 23 2014
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
T24gRnJpLCBNYXkgMzEsIDIwMTMgYXQgMTI6MTIgUE0sIEFsaSDDh2VocmVsaSA8YWNlaHJlbGlA eWFob28uY29tPiB3cm90ZToNCj4gc3RydWN0IFBhaXIgew0KPiAgIGRvdWJsZSB4LCB5Ow0KPiB9 DQo+DQo+IHZvaWQgbWFpbigpDQo+IHsNCj4gICAgIGF1dG8gcDAgPSBQYWlyKCk7DQo+ICAgICBh dXRvIHAxID0gUGFpcigxLjUpOyAgICAgICAgLy8gb25seSBwMS55IGlzIDANCg0KV291bGRuJ3Qg cDEueSBhY3R1YWxseSBiZSBOYU4gYW5kIG5vdCAwPw0KDQotLSANClNocmlyYW1hbmEgU2hhcm1h IOCutuCvjeCusOCvgOCusOCuruCuo+CutuCusOCvjeCuruCuviDgpLbgpY3gpLDgpYDgpLDgpK7g pKPgpLbgpLDgpY3gpK7gpL4NCg==
May 31 2013
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
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: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.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 &?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) { /* ... */ }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'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?
May 31 2013
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
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: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.comIn 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 thisThat 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 andmaybe useD for future ones. Advice?I will let you and others answer that question. Ali
May 31 2013
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
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
VGhhbmtzIEpvbmF0aGFuIGFuZCBBbGkgZm9yIGFsbCB0aG9zZSBjbGFyaWZpY2F0aW9ucy4NCg0K LS0gDQpTaHJpcmFtYW5hIFNoYXJtYSDgrrbgr43grrDgr4DgrrDgrq7grqPgrrbgrrDgr43grq7g rr4g4KS24KWN4KSw4KWA4KSw4KSu4KSj4KS24KSw4KWN4KSu4KS+DQo=
May 31 2013
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: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 DavisIn 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?
May 31 2013
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: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).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?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
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: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 DavisSo 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?!
May 31 2013