Jump to page: 1 2
Thread overview
A simplification of the RvalueRef idiom
Nov 21, 2016
Ali Çehreli
Nov 22, 2016
Nordlöw
Nov 22, 2016
Nordlöw
Nov 22, 2016
Ali Çehreli
Nov 22, 2016
Namespace
Nov 24, 2016
TheGag96
Nov 24, 2016
ketmar
Nov 24, 2016
Jonathan M Davis
Nov 25, 2016
Nick Treleaven
Nov 27, 2016
Nick Treleaven
Nov 22, 2016
Nordlöw
Nov 22, 2016
Guillaume Piolat
Nov 22, 2016
Satoshi
Nov 22, 2016
kink
Nov 22, 2016
Guillaume Piolat
Nov 22, 2016
Ali Çehreli
Nov 22, 2016
Satoshi
Nov 22, 2016
Satoshi
Nov 23, 2016
Stefan Koch
Nov 23, 2016
Era Scarecrow
November 21, 2016
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
November 22, 2016
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?
November 22, 2016
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?
November 22, 2016
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

November 22, 2016
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?
November 22, 2016
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 ;)
November 22, 2016
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.
November 22, 2016
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

November 22, 2016
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. ;)
November 22, 2016
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

« First   ‹ Prev
1 2