Thread overview
Voldemort type "this" pointer
Apr 21, 2021
realhet
Apr 21, 2021
Mike Parker
Apr 21, 2021
realhet
Apr 21, 2021
Ali Çehreli
Apr 22, 2021
realhet
April 21, 2021

Hi,

I noticed that there is a hidden "this" pointer in a struct that I declare inside a body of a function.
Also noticed when I use the "static" keyword, the "this" pointer disappears.

My question is about what is the "this" pointer for. Is it for storing the stack frame of the function in order to be able to serve queries that can lazily use the data from the stack frame?

(I guess it's something else because that part of the stack might be undefined after exiting from the function.)

April 21, 2021

On Wednesday, 21 April 2021 at 10:00:51 UTC, realhet wrote:

>

My question is about what is the "this" pointer for. Is it for storing the stack frame of the function in order to be able to serve queries that can lazily use the data from the stack frame?

(I guess it's something else because that part of the stack might be undefined after exiting from the function.)

From the documentation

>
  1. A nested struct is a struct that is declared inside the scope of a function or a templated struct that has aliases to local functions as a template argument. Nested structs have member functions. It has access to the context of its enclosing scope (via an added hidden field).
  2. A struct can be prevented from being nested by using the static attribute, but then of course it will not be able to access variables from its enclosing scope.

https://dlang.org/spec/struct.html#nested

April 21, 2021

On Wednesday, 21 April 2021 at 10:47:08 UTC, Mike Parker wrote:

>

On Wednesday, 21 April 2021 at 10:00:51 UTC, realhet wrote:

>

It has access to the context of its enclosing scope (via an added hidden field).

Thanks!

So it is unsafe to return a non-static nested struct from a function. But it is useful to pass it forward into other functions.

April 21, 2021
On 4/21/21 8:37 AM, realhet wrote:
> On Wednesday, 21 April 2021 at 10:47:08 UTC, Mike Parker wrote:
>> On Wednesday, 21 April 2021 at 10:00:51 UTC, realhet wrote:
>>
>>> It has access to the context of its enclosing scope (via an added hidden field).
> 
> Thanks!
> 
> So it is unsafe to return a non-static nested struct from a function. But it is useful to pass it forward into other functions.

Not at all. (D is good at preventing such bugs anyway.)

The local context that the nested struct object uses becomes the context of that object. Here is a poor person's proof (one can inspect the assembly output to observe delegate allocation as well):

import std.stdio;

auto foo() {
  int i;
  writeln(&i, " <- dynamic memory inside foo");

  struct S {
    void bar() {
      writeln(&i, " <- dynamic memory inside bar");
    }
  }

  return S();
}

void main() {
  int m;
  writeln(&m, " <- stack address inside main");
  auto s = foo();
  s.bar();
}

Sample output strongly suggests 'i' is not on the stack because the addresses are distant:

7FFFC14D85C0 <- stack address inside main
7FF424B9C008 <- dynamic memory inside foo
7FF424B9C008 <- dynamic memory inside bar

Ali
April 22, 2021
On Wednesday, 21 April 2021 at 15:53:59 UTC, Ali Çehreli wrote:
> On 4/21/21 8:37 AM, realhet wrote:
>> On Wednesday, 21 April 2021 at 10:47:08 UTC, Mike Parker wrote:
>>> On Wednesday, 21 April 2021 at 10:00:51 UTC, realhet wrote:
>>>
>>>> It has access to the context of its enclosing scope (via an added hidden field).
>> 
>> Thanks!
>> 
>> So it is unsafe to return a non-static nested struct from a function. But it is useful to pass it forward into other functions.
>
> Not at all. (D is good at preventing such bugs anyway.)
>
> The local context that the nested struct object uses becomes the context of that object.

Wow, this information is really out of the box for me. I have one misconception less now.
(I never used a language with GC before and this thing requires a GC for sure.)

/-------------------------------------------------------
auto uiDeclare(void delegate() fun){
    struct UiObject{
        //void delegate() fun; <- not needed, it captures fun in the params
        void render(){ fun(); }
    }
    return UiObject();
}

long rec(long a, long c){ return a<c ? rec(a+1, c) : a; }

void main() {
    int a = 5;
    auto b = [ uiDeclare({ writeln("boop", a); }), uiDeclare({ writeln("boop", a+1); })];
    rec(0, 123456); // destroy the stack to make sure
    b.each!"a.render";
}

Indeed it's not using the stack. And it also works when a delegates captures its scope.
In my immediate GUI interface I'm using delegates all the time with the my misconception of I only allowed to call them from inside the function I passed them into.
For example: Row({ Text(clBlue, "Hello"); Img(`pictures\pic1.jpg`); }); will call the delegate from inside, not save it for later use.

And if I save the delegate inside the Row() function (I mark UI generating functions with a capital letter), it is protected from the GC and can be used later in rendering time... Too bad, the data it uses at that later moment is possibly changed already.

Anyways, I've learned a lot now. Thank you!