www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - New With Struct and Getting Class Object Pointers

reply Vijay Nayar <madric gmail.com> writes:
I have two brief questions.

Code that uses "new" to create struct objects appears to compile 
and run. Is this an actual language feature, to get structs on 
the heap?

void main()
{
	struct S {int data = 1;}
	S* s1 = new S();
	S* s2 = s1;
	S s3 = *s1;  // Still copies on assignment.
	s3.data = 2;
	assert(s1.data != s3.data);
}

Second question. const class variables may not be re-assigned, so 
if you need a variable that may be reassigned, but may never 
modify the underlying object, a const pointer can be useful.  
However, it seems that when gets the address of a class variable, 
you do not get the underlying address of the class object.

How do you get a pointer to the underlying class object?  Example 
of the problem:

void main()
{
	import std.stdio;
	class A { int data = 3; }
	A a = new A();

	void f(A a) {
         a.data = 4;
		writeln("&a = ", &a, ", a.data = ", a.data);
	}
	
     f(a);
     writeln("&a = ", &a, ", a.data = ", a.data);
}

// Output:
&a = 7FFEA6BA3158, a.data = 4  // Addresses are different, from 
different class variables.
&a = 7FFEA6BA3180, a.data = 4  // But the same underlying class 
object.

Especially if I'm several levels down the call stack, how do I 
get a pointer to the underlying class object?
Sep 30 2018
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 30/09/2018 8:29 PM, Vijay Nayar wrote:
 I have two brief questions.
 
 Code that uses "new" to create struct objects appears to compile and 
 run. Is this an actual language feature, to get structs on the heap?
 
 void main()
 {
      struct S {int data = 1;}
      S* s1 = new S();
      S* s2 = s1;
      S s3 = *s1;  // Still copies on assignment.
      s3.data = 2;
      assert(s1.data != s3.data);
 }
Yes. Uses a compiler hook to call into the GC, like with everything else.
Sep 30 2018
prev sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 30 September 2018 at 07:29:00 UTC, Vijay Nayar wrote:
 I have two brief questions.

 Code that uses "new" to create struct objects appears to 
 compile and run. Is this an actual language feature, to get 
 structs on the heap?

 void main()
 {
 	struct S {int data = 1;}
 	S* s1 = new S();
 	S* s2 = s1;
 	S s3 = *s1;  // Still copies on assignment.
 	s3.data = 2;
 	assert(s1.data != s3.data);
 }

 Second question. const class variables may not be re-assigned, 
 so if you need a variable that may be reassigned, but may never 
 modify the underlying object, a const pointer can be useful.  
 However, it seems that when gets the address of a class 
 variable, you do not get the underlying address of the class 
 object.

 How do you get a pointer to the underlying class object?  
 Example of the problem:

 void main()
 {
 	import std.stdio;
 	class A { int data = 3; }
 	A a = new A();

 	void f(A a) {
         a.data = 4;
 		writeln("&a = ", &a, ", a.data = ", a.data);
 	}
 	
     f(a);
     writeln("&a = ", &a, ", a.data = ", a.data);
 }

 // Output:
 &a = 7FFEA6BA3158, a.data = 4  // Addresses are different, from 
 different class variables.
 &a = 7FFEA6BA3180, a.data = 4  // But the same underlying class 
 object.

 Especially if I'm several levels down the call stack, how do I 
 get a pointer to the underlying class object?
the variable `a` is a pointer (well, actually reference) to the underlying data. void main() { import core.stdc.stdio; class A { int data = 3; } A a = new A(); void f(A a) { a.data = 4; printf("&a = %p, a = %p, a.data=%d\n", &a, a,a.data); } f(a); printf("&a = %p, a = %p, a.data=%d\n", &a,a, a.data); } &a = 0x7ffd0800acb8, a = 0x7fd6b05b0000, a.data=4 &a = 0x7ffd0800acd0, a = 0x7fd6b05b0000, a.data=4 The stack ^ the heap^ data on the heap^ The address of the variable a on the stack has different values across function calls, its value (the reference to the class data) remains the same, as does the data itself.
Sep 30 2018
parent reply Vijay Nayar <madric gmail.com> writes:
On Sunday, 30 September 2018 at 09:16:42 UTC, Nicholas Wilson 
wrote:
 On Sunday, 30 September 2018 at 07:29:00 UTC, Vijay Nayar wrote:
 Second question. const class variables may not be re-assigned, 
 so if you need a variable that may be reassigned, but may 
 never modify the underlying object, a const pointer can be 
 useful.  However, it seems that when gets the address of a 
 class variable, you do not get the underlying address of the 
 class object.
&a = 0x7ffd0800acb8, a = 0x7fd6b05b0000, a.data=4 &a = 0x7ffd0800acd0, a = 0x7fd6b05b0000, a.data=4 The stack ^ the heap^ data on the heap^ The address of the variable a on the stack has different values across function calls, its value (the reference to the class data) remains the same, as does the data itself.
Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? For example: void main() { class Thing {} class ThingSaver { // A const(Thing) could not be changed in setThing(). const(Thing)* t; void setThing(in Thing thing) { t = thing; // ERROR converting to pointer type! } const(Thing) getThing() const { return *t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); const(Thing) t2 = saver.getThing(); }
Sep 30 2018
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote:
 Is there a way to either have a constant reference to a class 
 that can be set to a new value, or is there a way to convert 
 the class variable to a class pointer?

 For example:

 void main()
 {
 	class Thing {}
 	class ThingSaver {
                 // A const(Thing) could not be changed in 
 setThing().
 		const(Thing)* t;

 		void setThing(in Thing thing) {
 			t = thing;  // ERROR converting to pointer type!
 		}
 		const(Thing) getThing() const {
 			return *t;
 		}
 	}
 	
 	Thing t1 = new Thing();

 	ThingSaver saver = new ThingSaver();
 	saver.setThing(t1);
 	const(Thing) t2 = saver.getThing();
 }
I think, what you are facing here, is the different notion of const, as used from C++. The reasoning about it is described for example here: http://jmdavisprog.com/articles/why-const-sucks.html Jonathan is much better therein as I am. However, there are approaches to solve what you want to do. For example, there is a Rebindable around: https://dlang.org/library/std/typecons/rebindable.html ´´´ import std.stdio; import std.typecons; void main() { class Thing {int dummy; } class ThingSaver { /* A const(Thing) could not be changed in setThing(), but a Rebindable can be reassigned, keeping t const. */ Rebindable!(const Thing) t; void setThing(in Thing thing) { t = thing; // No pointers in use :) } const(Thing) getThing() const { return t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); //saver.t.dummy = 5; fails as expected. const(Thing) t2 = saver.getThing(); } ´´´ I hope, I got your idea right...
Sep 30 2018
parent Vijay Nayar <madric gmail.com> writes:
On Sunday, 30 September 2018 at 10:28:25 UTC, Alex wrote:
 On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote:
 Is there a way to either have a constant reference to a class 
 that can be set to a new value, or is there a way to convert 
 the class variable to a class pointer?
I think, what you are facing here, is the different notion of const, as used from C++. The reasoning about it is described for example here: http://jmdavisprog.com/articles/why-const-sucks.html Jonathan is much better therein as I am. However, there are approaches to solve what you want to do. For example, there is a Rebindable around: https://dlang.org/library/std/typecons/rebindable.html ´´´ import std.stdio; import std.typecons; void main() { class Thing {int dummy; } class ThingSaver { /* A const(Thing) could not be changed in setThing(), but a Rebindable can be reassigned, keeping t const. */ Rebindable!(const Thing) t; void setThing(in Thing thing) { t = thing; // No pointers in use :) } const(Thing) getThing() const { return t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); //saver.t.dummy = 5; fails as expected. const(Thing) t2 = saver.getThing(); } ´´´ I hope, I got your idea right...
That pretty much hits the nail on the head, and you're exactly right about where my understanding was coming from (C++). In fact, I'm moving a lot of code from C++ to D and finding equivalents for a lot of high-performance index classes, which end up using this kind of pattern. Now I need to take the time to grok this article!
Sep 30 2018
prev sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote:
 Is there a way to either have a constant reference to a class 
 that can be set to a new value, or is there a way to convert 
 the class variable to a class pointer?
Alex has mentioned Rebindable, which is the answer to your first question. To answer your second question, no class A {} A a: `a` is always a (possibly null) reference to a class instance. You can have pointers to class references (which is what `&a` gives you) but that has two indirections between the variable and the data, which if you want high perf is probably not what you are looking for.
Sep 30 2018
parent Vijay Nayar <madric gmail.com> writes:
On Sunday, 30 September 2018 at 11:11:09 UTC, Nicholas Wilson 
wrote:
 On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote:
 Is there a way to either have a constant reference to a class 
 that can be set to a new value, or is there a way to convert 
 the class variable to a class pointer?
Alex has mentioned Rebindable, which is the answer to your first question. To answer your second question, no class A {} A a: `a` is always a (possibly null) reference to a class instance. You can have pointers to class references (which is what `&a` gives you) but that has two indirections between the variable and the data, which if you want high perf is probably not what you are looking for.
Thanks everyone for the insight. I also finished reading Jonathan's article: http://jmdavisprog.com/articles/why-const-sucks.html I've run into just about every single problem described there, but had no idea just how deep the problem goes. So it was a depressing read, but I'm glad to have the deeper understanding. I'm definitely more open now to see what "__mutable" could offer as was discussed at DConf2018, though I'm curious about how it would remain compatible with "immutable".
Oct 03 2018