www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - why property cannot be pass as ref ?

reply ChangLong <changlon gmail.com> writes:
=======
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 ?
Dec 20 2017
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Dec 20 2017
next sibling parent Mengu <mengukagan gmail.com> writes:
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
Dec 20 2017
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Dec 20 2017
parent reply ChangLong <changlon gmail.com> writes:
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.
Dec 29 2017
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Jan 02 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Jan 03 2018
parent ChangLong <changlon gmail.com> writes:
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
Jan 03 2018