www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A simplification of the RvalueRef idiom

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
First, a reminder that we have this great resource of D idioms:

 
https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-and-then-not-using-it

The link above has an idiom of mixing in a byRef() member function to a 
struct. I think I've simplified the template by moving typeof(this) 
inside it:

mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER ANY MORE
{
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
     {
         return this;
     }
}

struct Vector2f
{
     float x, y;

     this(float x, float y) pure nothrow
     {
         this.x = x;
         this.y = y;
     }

     mixin RvalueRef;            // <-- SIMPLER USE
}

void foo(ref const Vector2f pos)
{
     writefln("(%.2f|%.2f)", pos.x, pos.y);
}

void main()
{
     Vector2f v = Vector2f(42, 23);
     foo(v);                           // Works
     foo(Vector2f(42, 23).byRef);      // Works as well, and use the 
same function
}

Let me know if it's not the equivalent of the original.

Ali
Nov 21 2016
next sibling parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 Let me know if it's not the equivalent of the original.

 Ali
Nice. What about putting this in a druntime or phobos PR, making it standardized?
Nov 22 2016
prev sibling next sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER 
 ANY MORE
 {
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
Why do you need to qualify `byRef` as pure nothrow when it's a template?
Nov 22 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/22/2016 05:06 AM, Nordlöw wrote:
 On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER ANY MORE
 {
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
Why do you need to qualify `byRef` as pure nothrow when it's a template?
I don't think you need those. I didn't pay attention to any other part of the code other than moving that parameter inside. :) Ali
Nov 22 2016
prev sibling next sibling parent Namespace <rswhite4 gmail.com> writes:
On Tuesday, 22 November 2016 at 13:06:27 UTC, Nordlöw wrote:
 On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER 
 ANY MORE
 {
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
Why do you need to qualify `byRef` as pure nothrow when it's a template?
No need for these, but I did it out of habit ;)
Nov 22 2016
prev sibling parent reply TheGag96 <thegag96 gmail.com> writes:
On Tuesday, 22 November 2016 at 13:06:27 UTC, Nordlöw wrote:
 On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER 
 ANY MORE
 {
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
Why do you need to qualify `byRef` as pure nothrow when it's a template?
The thing that gets me more is "return" as a function attribute. I see it under "MemberFunctionAttribute" in the grammar but I can't find an explanation for its use anywhere...
Nov 23 2016
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Thursday, 24 November 2016 at 00:35:39 UTC, TheGag96 wrote:
 The thing that gets me more is "return" as a function 
 attribute. I see it under "MemberFunctionAttribute" in the 
 grammar but I can't find an explanation for its use anywhere...
YOU ARE NOT SUPPOSED TO KNOW THIS. DON'T LIVE YOUR PLACE, WE SENT A VAN FOR YOU.
Nov 23 2016
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, November 24, 2016 00:35:39 TheGag96 via Digitalmars-d-learn 
wrote:
 On Tuesday, 22 November 2016 at 13:06:27 UTC, Nordlw wrote:
 On Monday, 21 November 2016 at 20:04:51 UTC, Ali ehreli wrote:
 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER
 ANY MORE
 {

     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
Why do you need to qualify `byRef` as pure nothrow when it's a template?
The thing that gets me more is "return" as a function attribute. I see it under "MemberFunctionAttribute" in the grammar but I can't find an explanation for its use anywhere...
I believe that that has to do with DIP 25, which is enabled with the -dip25 compiler switch: http://wiki.dlang.org/DIP25 - Jonathan M Davis
Nov 24 2016
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Thursday, 24 November 2016 at 00:35:39 UTC, TheGag96 wrote:
 The thing that gets me more is "return" as a function 
 attribute. I see it under "MemberFunctionAttribute" in the 
 grammar but I can't find an explanation for its use anywhere...
I've started documenting it now, will post a PR soon.
Nov 25 2016
parent Nick Treleaven <nick geany.org> writes:
On Friday, 25 November 2016 at 17:21:52 UTC, Nick Treleaven wrote:
 I've started documenting it now, will post a PR soon.
https://github.com/dlang/dlang.org/pull/1519
Nov 27 2016
prev sibling next sibling parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
     ref const(T) byRef() const pure nothrow return
Add when DIP-1000 has been implemented into compiler this should be `scope`-qualified aswell, right?
Nov 22 2016
prev sibling next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 Let me know if it's not the equivalent of the original.

 Ali
I've changed the idiom, thanks. The place to discuss this is the d-idioms bugtracker, else I would have skipped this message.
Nov 22 2016
prev sibling parent reply Satoshi <satoshi gshost.eu> writes:
On Monday, 21 November 2016 at 20:04:51 UTC, Ali Çehreli wrote:
 First, a reminder that we have this great resource of D idioms:


 https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-and-then-not-using-it

 The link above has an idiom of mixing in a byRef() member 
 function to a struct. I think I've simplified the template by 
 moving typeof(this) inside it:

 mixin template RvalueRef()    // <-- DOES NOT TAKE A PARAMETER 
 ANY MORE
 {
     alias T = typeof(this);
     static assert (is(T == struct));

      nogc  safe
     ref const(T) byRef() const pure nothrow return
     {
         return this;
     }
 }

 struct Vector2f
 {
     float x, y;

     this(float x, float y) pure nothrow
     {
         this.x = x;
         this.y = y;
     }

     mixin RvalueRef;            // <-- SIMPLER USE
 }

 void foo(ref const Vector2f pos)
 {
     writefln("(%.2f|%.2f)", pos.x, pos.y);
 }

 void main()
 {
     Vector2f v = Vector2f(42, 23);
     foo(v);                           // Works
     foo(Vector2f(42, 23).byRef);      // Works as well, and use 
 the same function
 }

 Let me know if it's not the equivalent of the original.

 Ali
Sorry, but D seems to be worse and worse day by day. This should be resolved by language and not doing it by template function. Same thing should be applied for maybe monad and tuples. e.g. When I want to create simple function for drawing void lineTo(auto ref Point point...) { //... } It's easier to call it like: Point p = Point(42, 42); lineTo(p); lineTo(42, 42); lineTo(Point(42, 42)); // this lineTo(Point(42, 42).byRef); // and this is just overhead Everything possible should be solved by syntactic sugar rather than implementing it as template func. Or just remove shared, TLS and other stuff from D and implement it as templates like in C++. Then you can write much more longer and uglier stuffs as you trying. void lineTo(std::shared_ptr<Point> point) { // ... } lineTo(std::make<Point>(42, 42)); should be ideal way how to complicate programming for other users. Sorry, but I want to write fast and safe programs in the fastest possible way and writing Point(...) or Point(...).byRef every time is redundant overhead. Like http://pix.toile-libre.org/upload/original/1479816672.png PS: sorry for sarcasm - Satoshi
Nov 22 2016
next sibling parent reply kink <noone nowhere.com> writes:
On Tuesday, 22 November 2016 at 16:05:35 UTC, Satoshi wrote:
 Sorry, but D seems to be worse and worse day by day.
 This should be resolved by language and not doing it by 
 template function.
I hate this 'idiom' too (just a clumsy workaround for something that should work out of the box), but the non-bindability of rvalues to ref params and the associated dispute is veeery old, nothing new, so I don't agree that the language gets worse every day. ;)
Nov 22 2016
parent Guillaume Piolat <first.last gmail.com> writes:
On Tuesday, 22 November 2016 at 16:57:28 UTC, kink wrote:
 I hate this 'idiom' too (just a clumsy workaround for something 
 that should work out of the box), but the non-bindability of 
 rvalues to ref params and the associated dispute is veeery old, 
 nothing new, so I don't agree that the language gets worse 
 every day. ;)
d-idioms doesn't always paint a rosy picture of D, that's true. It's about "what can we do now with D, whatever it takes". It turns out almost everything can be done, but some things are worse than in other languages of course. The baby is too cute to throw with the bathwater ;)
Nov 22 2016
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/22/2016 08:05 AM, Satoshi wrote:

 Sorry, but D seems to be worse and worse day by day.
I don't have extensive experience with other languages. In fact, the only other languages that I can claim proficiency are C and C++. (I also know Python just enough to find it incredible how it's used in the industry. Let's not get in to that discussion but I really tried and failed... in industry... :) ) Given that experience, I still find D a very useful tool.
 This should be resolved by language and not doing it by template 
function. byRef() is not implicit due to a deliberae design decision. Walter talks about why the language lacks ref variables in his recent talk. No, I was not there and the audio is lost, so all we have at this point are the slides. It's the "Memory Safety and the D Programming Languge" presentation http://www.walterbright.com/ Slide 26 starts talking about ref and why it's only for parameters and returns.
 Same thing should be applied for maybe monad and tuples.

 e.g. When I want to create simple function for drawing

 void lineTo(auto ref Point point...) {
 //...
 }

 It's easier to call it like:
 Point p = Point(42, 42);

 lineTo(p);
 lineTo(42, 42);
Agreed but it opens the door for bugs. Assuming struct A { int a; } struct B { int b; int c; } void foo(int, int, int); If foo(1, 2, 3) meant foo(A(1), B(2, 3)) today, it could silently mean foo(A(1, 2), B(3)) if one moved one member from one struct to the other. Then there are other corner cases: writeln(1, 2, 3); Should that print the integers or A(1) and B(2, 3)? It's always better to be explicit.
 lineTo(Point(42, 42)); // this
 lineTo(Point(42, 42).byRef); // and this is just overhead
I don't agree with those two examples but e.g. I find the following cumbersome: A[] arr = [ A(1), A(2) ];
 Sorry, but I want to write fast and safe programs in the fastest
 possible way
I think in these examples 'fast' and 'safe' don't work together.
 and writing Point(...) or Point(...).byRef every time is
 redundant overhead.

 Like http://pix.toile-libre.org/upload/original/1479816672.png


 PS: sorry for sarcasm
 - Satoshi
Agreed but I find solutions like the following acceptable. Yes, function names must be different but it's usually fine. import std.stdio; struct Point { int x; int y; } struct GraphicsContext { static GraphicsContext current() { return GraphicsContext(); } void moveTo(Point point) { writefln("Moving to %s", point); } void lineTo(Point point) { writefln("Drawing line to %s", point); } } void goTo(GraphicsContext gc, int x, int y) { gc.moveTo(Point(x, y)); } void drawTo(GraphicsContext gc, int x, int y) { gc.lineTo(Point(x, y)); } void main() { auto gc = GraphicsContext.current; gc.goTo(70, 70); // <-- Clean syntax gc.drawTo(70, 170); } Ali
Nov 22 2016
parent reply Satoshi <satoshi rikarin.org> writes:
On Tuesday, 22 November 2016 at 19:16:56 UTC, Ali Çehreli wrote:
 On 11/22/2016 08:05 AM, Satoshi wrote:
 I don't have extensive experience with other languages. In 
 fact, the only other languages that I can claim proficiency are 
 C and C++. (I also know Python just enough to find it 
 incredible how it's used in the industry. Let's not get in to 
 that discussion but I really tried and failed... in industry... 
 :) ) Given that experience, I still find D a very useful tool.
D is one o the best languages what exists, it's reason why I'm using it. But some issues are solved better in other languages like rust, go or swift.
 Agreed but it opens the door for bugs. Assuming

 struct A { int a; }
 struct B { int b; int c; }

 void foo(int, int, int);

 If foo(1, 2, 3) meant foo(A(1), B(2, 3)) today, it could 
 silently mean foo(A(1, 2), B(3)) if one moved one member from 
 one struct to the other.

 Then there are other corner cases:

     writeln(1, 2, 3);

 Should that print the integers or A(1) and B(2, 3)? It's always 
 better to be explicit.
argument expand should be applied only to the last argument and cannot be used in variadic templates. Like in my simple example where I exactly know what function will do, but I want to call it by simplest way. It actually works with classes, but no with structs.
 import std.stdio;

 struct Point {
     int x;
     int y;
 }

 struct GraphicsContext {
     static GraphicsContext current() {
         return GraphicsContext();
     }

     void moveTo(Point point) {
         writefln("Moving to %s", point);
     }

     void lineTo(Point point) {
         writefln("Drawing line to %s", point);
     }
 }

 void goTo(GraphicsContext gc, int x, int y) {
     gc.moveTo(Point(x, y));
 }

 void drawTo(GraphicsContext gc, int x, int y) {
     gc.lineTo(Point(x, y));
 }

 void main() {
     auto gc = GraphicsContext.current;
     gc.goTo(70, 70);    // <-- Clean syntax
     gc.drawTo(70, 170);
 }
But I need to write overload function for every function taking simple messengers like Point/Size/Rectangle
Nov 22 2016
parent reply Satoshi <satoshi rikarin.org> writes:
or I have simple class

class View {
this(Rectangle frame) {...}
this(float, float, float, float) { ... }
this(Point, Size) { ... }
}

then struct Point, Size and Rectangle (Point, Size)

now I need to write 2 overloads for View class taking 4 floats or 
(Point, Size) and this must do in every descendant of View class.
Nov 22 2016
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 22 November 2016 at 22:03:14 UTC, Satoshi wrote:
 or I have simple class

 class View {
 this(Rectangle frame) {...}
 this(float, float, float, float) { ... }
 this(Point, Size) { ... }
 }

 then struct Point, Size and Rectangle (Point, Size)

 now I need to write 2 overloads for View class taking 4 floats 
 or (Point, Size) and this must do in every descendant of View 
 class.
This can be solved with string-mixins.
Nov 22 2016
prev sibling parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 22 November 2016 at 16:05:35 UTC, Satoshi wrote:
 Sorry, but D seems to be worse and worse day by day. This 
 should be resolved by language and not doing it by template 
 function.
 Same thing should be applied for maybe monad and tuples.
I'm reminded of trying to follow the rules and do both L&R types, and I came across unwanted behavior since the qualifiers would make something the wrong type because constness was closer matching, among other weird behavior. I'll hope more of this gets resolved, and then I can look at the language seriously and really do something with it.
Nov 22 2016