Thread overview
why @property cannot be pass as ref ?
Dec 20, 2017
ChangLong
Dec 20, 2017
Ali Çehreli
Dec 20, 2017
Mengu
Dec 20, 2017
Ali Çehreli
Dec 30, 2017
ChangLong
Jan 02, 2018
Ali Çehreli
Jan 03, 2018
Simen Kjærås
Jan 04, 2018
ChangLong
December 20, 2017
=======
struct A {
		alias This	= typeof(this) ;
		
		void opAssign(ref This ){
		}
		
		ref auto left(){
			return This() ;
		}
}

void main(){
	A	root ;
	ref find() {
	    auto p = root ;
	    p = p.left;
	}
}
===========

test.d(16): Error: function tree.A.opAssign (ref A _param_0) is not callable using argument types (A)


Is this by design ?

December 20, 2017
On 12/20/2017 07:02 AM, ChangLong wrote:
> =======
> struct A {
>          alias This    = typeof(this) ;
>
>          void opAssign(ref This ){
>          }
>
>          ref auto left(){
>              return This() ;
>          }
> }
>
> void main(){
>      A    root ;
>      ref find() {
>          auto p = root ;
>          p = p.left;
>      }
> }
> ===========
>
> test.d(16): Error: function tree.A.opAssign (ref A _param_0) is not
> callable using argument types (A)
>
>
> Is this by design ?

The problem is not with opAssign but with left(), which returns an rvalue. It's by design that rvalues cannot be bound to references in D.

The code compiles if left() returns an lvalue:

        ref auto left(){
            //            return This() ;
            return *l;
        }

        This *l;

What you can do is to convert opAssign to a template with an additional set of parameters and change its parameter to 'auto ref':

        void opAssign()(auto ref This ){
        }

'auto ref' essentially generates two copies of the function: one taking by-value for rvalues and one taking by-ref for lvalues. So, be aware that you cannot use the address of the argument because in the case of rvalues its a local variable (copy of the actual argument).

Ali

December 20, 2017
On Wednesday, 20 December 2017 at 18:04:57 UTC, Ali Çehreli wrote:
> On 12/20/2017 07:02 AM, ChangLong wrote:
> > [...]
> is not
> > [...]
>
> The problem is not with opAssign but with left(), which returns an rvalue. It's by design that rvalues cannot be bound to references in D.
>
> [...]

was just reading this: https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-and-then-not-using-it
December 20, 2017
Thanks to Mengü for linking to that section. I have to make corrections below.

On 12/20/2017 10:04 AM, Ali Çehreli wrote:

> 'auto ref' essentially generates two copies of the function: one taking
> by-value for rvalues

Note that by-value for rvalues means "blitting" in D (blit: bit-level transfer).

> in the case of
> rvalues its a local variable (copy of the actual argument).

I was wrong there: The local variable is the actual argument blitted in to the function.

The post-blit is never executed for rvalues. The following program does *not* print "post-blit":

import std.stdio;

struct S {
    int i;
    this (int i) {
        this.i = i;
        writeln("&this  : ", &this);
    }

    this(this) {
        writeln("post-blit");
    }
}

void foo()(auto ref S s) {
    writeln("&s     : ", &s);
}

void main() {
    auto lvalue = S(1);
    foo(lvalue);
    foo(S(2)); // rvalue
}

&this  : 7FFF23ED08A8    <-- lvalue
&s     : 7FFF23ED08A8    <-- by-ref lvalue
&this  : 7FFF23ED08AC    <-- rvalue
&s     : 7FFF23ED0890    <-- blitted rvalue

Ali

December 30, 2017
On Wednesday, 20 December 2017 at 18:43:21 UTC, Ali Çehreli wrote:
> Thanks to Mengü for linking to that section. I have to make corrections below.
>
> Ali


Thanks for explain, Ali And Mengu.

What I am try to do is implement a unique data type. (the ownership auto moved into new handle)

consider this code:

import std.stdio;

struct S {
        @disable this(this);
    void* socket;
    this (void* i) {
        socket = i;
    }

    void opAssign()(auto ref S s ){
        socket = s.socket ;
        s.socket = null ;
    }

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


void main() {
    static __gshared size_t socket;
    auto lvalue = S(&socket);   // pass rvalue into lvalue, working
    S l2 =  void;
    l2 = lvalue;        // pass lvalue into lvalue, working
    auto l3 = l2.byRef; // pass lvalue into lvalue, not working
}



I can not assign  l2 to l3 because "Error: struct app.S is not copyable because it is annotated with @disable", but it working if I init l3 with void.






January 02, 2018
On 12/29/2017 07:49 PM, ChangLong wrote:
> On Wednesday, 20 December 2017 at 18:43:21 UTC, Ali Çehreli wrote:
>> Thanks to Mengü for linking to that section. I have to make corrections below.
>>
>> Ali
> 
> 
> Thanks for explain, Ali And Mengu.
> 
> What I am try to do is implement a unique data type. (the ownership auto moved into new handle)
> 
> consider this code:
> 
> import std.stdio;
> 
> struct S {
>          @disable this(this);
>      void* socket;
>      this (void* i) {
>          socket = i;
>      }
> 
>      void opAssign()(auto ref S s ){
>          socket = s.socket ;
>          s.socket = null ;
>      }
> 
>      @nogc @safe
>      ref auto byRef() const pure nothrow return
>      {
>          return this;
>      }
> }
> 
> 
> void main() {
>      static __gshared size_t socket;
>      auto lvalue = S(&socket);   // pass rvalue into lvalue, working
>      S l2 =  void;
>      l2 = lvalue;        // pass lvalue into lvalue, working
>      auto l3 = l2.byRef; // pass lvalue into lvalue, not working
> }
> 
> 
> 
> I can not assign  l2 to l3 because "Error: struct app.S is not copyable because it is annotated with @disable", but it working if I init l3 with void.

I hope others can answer that. For what it's worth, here is an earlier experiment that Vittorio Romeo and I had played with at C++Now 2017. It uses std.algorithm.move:

import std.stdio;
import std.algorithm;

int allocate() {
    static int i = 42;
    writeln("allocating ", i);
    return i++;
}

void deallocate(int i) {
    writeln("deallocating ", i);
}

struct UniquePtr {
    int i = 666;    // To easily differentiate UniquePtr.init from 0
    this(int i) {
        this.i = i;
    }

    ~this() {
        deallocate(i);
    }

    @disable this(this);
}

void use(UniquePtr p) {
    writeln("using ", p.i);
}

UniquePtr producer_rvalue(int i) {
    return i % 2 ? UniquePtr(allocate()) : UniquePtr(allocate());
}

UniquePtr producer_lvalue() {
    writeln("producer_lvalue");
    auto u = UniquePtr(allocate());
    writeln("allocated lvalue ", u.i);
    return u;
}

void main() {
    use(UniquePtr(allocate()));

    auto u = UniquePtr(allocate());
    use(move(u));

    auto p = producer_rvalue(0);
    use(move(p));
    auto p2 = producer_lvalue();
    use(move(p2));
}

Ali


January 03, 2018
On Saturday, 30 December 2017 at 03:49:37 UTC, ChangLong wrote:
> What I am try to do is implement a unique data type. (the ownership auto moved into new handle)

Have you considered std.typecons.Unique[0]? If yes, in what ways does it not cover your needs?

Your example code written with Unique would be something like the below, with some additions to show off more of what it can do:

import std.typecons : Unique;
import std.algorithm.mutation : move;

void test1(size_t i) {}
void test2(ref size_t i) {}
void test3(ref Unique!size_t i) {}
void test4(Unique!size_t i) {}

unittest
{
    static __gshared size_t socket;
    auto l1 = Unique!(size_t)(&socket);
    assert(l1 == &socket);

    Unique!(size_t) l2 = void;
    assert(!is(typeof({
        l2 = l1; // Fails to compile - cannot copy Unique.
    })));
    move(l1, l2); // Explicit move using std.algorithm.mutation.move.

    assert(l1 == null); // l1 has been cleared - only one reference to the data exists.
    assert(l2 == &socket); // l2 has the only reference.

    auto l3 = l2.release; // Implicit move, not unlike your byRef call.

    assert(l2 == null); // l2 has been cleared - only one reference to the data exists.
    assert(l3 == &socket); // l3 has the only reference.

    assert(!is(typeof({
        auto l4 = l3; // Fails to compile - cannot copy Unique.
    })));

    test1(*l3); // Can dereference and pass the pointed-to value.
    test2(*l3); // Can pass reference to pointed-to value[1].
    test3(l3);  // Lets you pass references to Unique.
    assert(!is(typeof({
        test4(l3); // Fails to compile - cannot copy Unique.
    })));
}

[0]: https://dlang.org/library/std/typecons/unique.html
[1]: This surprised me a little - that's a new reference to the pointed-to value, which the callee could squirrel away somewhere it shouldn't. I guess it's there for ease of use.

--
  Simen
January 04, 2018
On Wednesday, 3 January 2018 at 08:51:55 UTC, Simen Kjærås wrote:
> On Saturday, 30 December 2017 at 03:49:37 UTC, ChangLong wrote:
>> What I am try to do is implement a unique data type. (the ownership auto moved into new handle)
>
> Have you considered std.typecons.Unique[0]? If yes, in what ways does it not cover your needs?
>
> Your example code written with Unique would be something like the below, with some additions to show off more of what it can do:
>
> import std.typecons : Unique;
> import std.algorithm.mutation : move;
>
> void test1(size_t i) {}
> void test2(ref size_t i) {}
> void test3(ref Unique!size_t i) {}
> void test4(Unique!size_t i) {}
>
> unittest
> {
>     static __gshared size_t socket;
>     auto l1 = Unique!(size_t)(&socket);
>     assert(l1 == &socket);
>
>     Unique!(size_t) l2 = void;
>     assert(!is(typeof({
>         l2 = l1; // Fails to compile - cannot copy Unique.
>     })));
>     move(l1, l2); // Explicit move using std.algorithm.mutation.move.
>
>     assert(l1 == null); // l1 has been cleared - only one reference to the data exists.
>     assert(l2 == &socket); // l2 has the only reference.
>
>     auto l3 = l2.release; // Implicit move, not unlike your byRef call.
>
>     assert(l2 == null); // l2 has been cleared - only one reference to the data exists.
>     assert(l3 == &socket); // l3 has the only reference.
>
>     assert(!is(typeof({
>         auto l4 = l3; // Fails to compile - cannot copy Unique.
>     })));
>
>     test1(*l3); // Can dereference and pass the pointed-to value.
>     test2(*l3); // Can pass reference to pointed-to value[1].
>     test3(l3);  // Lets you pass references to Unique.
>     assert(!is(typeof({
>         test4(l3); // Fails to compile - cannot copy Unique.
>     })));
> }
>
> [0]: https://dlang.org/library/std/typecons/unique.html
> [1]: This surprised me a little - that's a new reference to the pointed-to value, which the callee could squirrel away somewhere it shouldn't. I guess it's there for ease of use.
>
> --
>   Simen

Thanks for explain. I need add version number and other check into the UniqueType,  std.typecons : Unique is is not suit.

std.algorithm.mutation : move is what I am look for.  but I don't understand why this code not working since I already add void opAssign(ref This ) to UniqueType.

 Unique!(size_t) l1 =  Unique!(size_t)(&socket);
 Unique!(size_t) l2 = void;
 l2 = l1;  // assign left value into left value,  Unique is not copyable because it is annotated with @disable