www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Storing a reference

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
I just figured out how to store a reference:

 safe:
auto x(ref int a) {
	struct A {
		ref int xa() { return a; }
	}
	return A();
}
void main() {
	import std.stdio;
	int b = 10;
	auto a = x(b);
	a.xa = 20;
	writeln(b); //Prints 20
}

I have no idea if this is a right thing to do. Can someone tell 
me if this is idiomatic D, and whether there're any catches to 
this method or not?

Thanks.
Sep 01 2016
parent reply Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui wrote:
 I just figured out how to store a reference:

  safe:
 auto x(ref int a) {
 	struct A {
 		ref int xa() { return a; }
 	}
 	return A();
 }
 void main() {
 	import std.stdio;
 	int b = 10;
 	auto a = x(b);
 	a.xa = 20;
 	writeln(b); //Prints 20
 }

 I have no idea if this is a right thing to do. Can someone tell 
 me if this is idiomatic D, and whether there're any catches to 
 this method or not?

 Thanks.
This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value.
Sep 01 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 1 September 2016 at 20:28:03 UTC, Rene Zwanenburg 
wrote:
 On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui 
 wrote:
 [...]
This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value.
I think my approach is probably better, because I believe (correct me if I'm wrong): 1) it will never refer to a null object. 2) after DIP1000 is implemented we will be able to make sure there will be no dangling reference.
Sep 01 2016
next sibling parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Thursday, 1 September 2016 at 20:38:13 UTC, Yuxuan Shui wrote:
 I think my approach is probably better, because I believe 
 (correct me if I'm wrong): 1) it will never refer to a null 
 object.
That's true, but you can ensure the same thing for the wrapper: struct Ref() { disable this(); this(T* value) { assert(value !is null); this.value = value; } // rest same as before }
 2) after DIP1000 is implemented we will be able to make sure 
 there will be no dangling reference.
I'm not very familiar with the details of DIP1000, so I can't comment on that.
Sep 01 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/1/16 4:38 PM, Yuxuan Shui wrote:
 On Thursday, 1 September 2016 at 20:28:03 UTC, Rene Zwanenburg wrote:
 On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui wrote:
 [...]
This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value.
I think my approach is probably better, because I believe (correct me if I'm wrong): 1) it will never refer to a null object. 2) after DIP1000 is implemented we will be able to make sure there will be no dangling reference.
Referring to a null object is not a problem. Your program crashes ungracefully, but does not corrupt memory. However, in either approach, it can easily end up being a dangling pointer. But to refer to a null location is quite easy: int *foo; // null ptr auto a = x(*foo); assert(&a.xa() == null); Your approach is less desirable because of the closure to point at a given reference which can be had with just a reference. Needless allocation. -Steve
Sep 01 2016
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 1 September 2016 at 21:07:36 UTC, Steven 
Schveighoffer wrote:
 On 9/1/16 4:38 PM, Yuxuan Shui wrote:
 [...]
Referring to a null object is not a problem. Your program crashes ungracefully, but does not corrupt memory. However, in either approach, it can easily end up being a dangling pointer. But to refer to a null location is quite easy: int *foo; // null ptr auto a = x(*foo); assert(&a.xa() == null); Your approach is less desirable because of the closure to point at a given reference which can be had with just a reference. Needless allocation. -Steve
Makes sense. Thanks!
Sep 01 2016