Thread overview
New With Struct and Getting Class Object Pointers
Sep 30, 2018
Vijay Nayar
Sep 30, 2018
rikki cattermole
Sep 30, 2018
Nicholas Wilson
Sep 30, 2018
Vijay Nayar
Sep 30, 2018
Alex
Sep 30, 2018
Vijay Nayar
Sep 30, 2018
Nicholas Wilson
Oct 03, 2018
Vijay Nayar
September 30, 2018
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?
September 30, 2018
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.
September 30, 2018
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.

September 30, 2018
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();
}
September 30, 2018
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...
September 30, 2018
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!

September 30, 2018
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.
October 03, 2018
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".