Thread overview
Get parent function of nested delegate
February 16

I want to get a reference to a parent function from inside a nested function. I need it for getUDAs!(parentFunction, attribute).

__traits(parent, mixin(__FUNCTION__)) works inside the parent function and gives me the module, but mixin(__FUNCTION__) alone inside the nested function immediately errors.

module foo;

void bar(string s, int i)
{
    assert(__FUNCTION__ == "foo.bar");
    alias parentModule = __traits(parent, mixin(__FUNCTION__));
    assert(is(parentModule == module));

    void dg()
    {
        assert(__FUNCTION__ == "foo.bar.dg");
        alias parentFunction = __traits(parent, mixin(__FUNCTION__));
    }
}

void main() {}
onlineapp.d(12): Error: function `bar` is not callable using argument types `()`
onlineapp.d(12):        too few arguments, expected 2, got 0
onlineapp.d(3):        `foo.bar(string s, int i)` declared here

So mixin(__FUNCTION__) seems to be trying to call the parent function rather than giving me the symbol of the nested one, like foo.bar().dg. I tried making it mixin("&" ~ __FUNCTION__) but it did not help.

How can I make this work?

February 16

On Sunday, 16 February 2025 at 07:38:09 UTC, Anonymouse wrote:

>

How can I make this work?

As a workaround, you can define a useless symbol and get the parent of that.

module foo;

void bar(string s, int i)
{
    assert(__FUNCTION__ == "foo.bar");
    alias parentModule = __traits(parent, mixin(__FUNCTION__));
    assert(is(parentModule == module));

    void dg()
    {
        assert(__FUNCTION__ == "foo.bar.dg");
	enum n = 0;
        alias parentFunction = __traits(parent, __traits(parent, n));
	pragma(msg, __traits(identifier, parentFunction)); // bar
	pragma(msg, __traits(identifier, __traits(parent, n))); // dg

    }
}

void main() {}
March 17
On Sunday, February 16, 2025 12:38:09 AM MDT Anonymouse via Digitalmars-d-learn wrote:
> I want to get a reference to a parent function from inside a nested function. I need it for `getUDAs!(parentFunction, attribute)`.
>
> `__traits(parent, mixin(__FUNCTION__))` works inside the parent
> function and gives me the module, but `mixin(__FUNCTION__)` alone
> inside the nested function immediately errors.
>
> ```d
> module foo;
>
> void bar(string s, int i)
> {
>      assert(__FUNCTION__ == "foo.bar");
>      alias parentModule = __traits(parent, mixin(__FUNCTION__));
>      assert(is(parentModule == module));
>
>      void dg()
>      {
>          assert(__FUNCTION__ == "foo.bar.dg");
>          alias parentFunction = __traits(parent,
> mixin(__FUNCTION__));
>      }
> }
>
> void main() {}
> ```
>
> ```
> onlineapp.d(12): Error: function `bar` is not callable using
> argument types `()`
> onlineapp.d(12):        too few arguments, expected 2, got 0
> onlineapp.d(3):        `foo.bar(string s, int i)` declared here
> ```
>
> So `mixin(__FUNCTION__)` seems to be trying to call the parent
> function rather than giving me the symbol of the nested one, like
> `foo.bar().dg`. I tried making it `mixin("&" ~ __FUNCTION__)` but
> it did not help.
>
> How can I make this work?

If I had to guess, the problem is that when you're passing the name of the function to __traits(parent, ...), it's grabbing that symbol via the normal lookup rules, meaning that the visibility rules apply, and nested functions are not visible from outside the function. Now, you're inside the function in the example, but since you don't normally use the full path for a nested function when using it, the compiler probably isn't even set up to do so. I would guess that it was simply never thought of.

Really, what would be ideal here would be something like __FUNCTION_SYMBOL__ which gave the symbol of the function rather than its name as a string, since that would bypass this whole issue (as well as negate the need to use a mixin to get the symbol for the function).

However, there is a pretty simple workaround. Just get the symbol from within the parent function instead of within the nested function, e.g.

    alias parentFunction = mixin(__FUNCTION__);

    void dg()
    {
        // access parentFunction here
    }

It even works if the nested function is static.

- Jonathan M Davis



March 17
On Monday, March 17, 2025 6:28:19 PM MDT Jonathan M Davis via Digitalmars-d-learn wrote:
> On Sunday, February 16, 2025 12:38:09 AM MDT Anonymouse via Digitalmars-d-learn wrote:
> > I want to get a reference to a parent function from inside a nested function. I need it for `getUDAs!(parentFunction, attribute)`.
> >
> > `__traits(parent, mixin(__FUNCTION__))` works inside the parent
> > function and gives me the module, but `mixin(__FUNCTION__)` alone
> > inside the nested function immediately errors.
> >
> > ```d
> > module foo;
> >
> > void bar(string s, int i)
> > {
> >      assert(__FUNCTION__ == "foo.bar");
> >      alias parentModule = __traits(parent, mixin(__FUNCTION__));
> >      assert(is(parentModule == module));
> >
> >      void dg()
> >      {
> >          assert(__FUNCTION__ == "foo.bar.dg");
> >          alias parentFunction = __traits(parent,
> > mixin(__FUNCTION__));
> >      }
> > }
> >
> > void main() {}
> > ```
> >
> > ```
> > onlineapp.d(12): Error: function `bar` is not callable using
> > argument types `()`
> > onlineapp.d(12):        too few arguments, expected 2, got 0
> > onlineapp.d(3):        `foo.bar(string s, int i)` declared here
> > ```
> >
> > So `mixin(__FUNCTION__)` seems to be trying to call the parent
> > function rather than giving me the symbol of the nested one, like
> > `foo.bar().dg`. I tried making it `mixin("&" ~ __FUNCTION__)` but
> > it did not help.
> >
> > How can I make this work?
>
> If I had to guess, the problem is that when you're passing the name of the function to __traits(parent, ...), it's grabbing that symbol via the normal lookup rules, meaning that the visibility rules apply, and nested functions are not visible from outside the function. Now, you're inside the function in the example, but since you don't normally use the full path for a nested function when using it, the compiler probably isn't even set up to do so. I would guess that it was simply never thought of.
>
> Really, what would be ideal here would be something like __FUNCTION_SYMBOL__ which gave the symbol of the function rather than its name as a string, since that would bypass this whole issue (as well as negate the need to use a mixin to get the symbol for the function).
>
> However, there is a pretty simple workaround. Just get the symbol from within the parent function instead of within the nested function, e.g.
>
>     alias parentFunction = mixin(__FUNCTION__);
>
>     void dg()
>     {
>         // access parentFunction here
>     }
>
> It even works if the nested function is static.

Actually, when I went to create an enhancement request for __FUNCTION_SYMBOL__ and did some digging to see what already exists, I found out about this trick:

    __traits(parent, {})

will give you the symbol for the current function, making it similar to

    __traits(parent, mixin(__FUNCTION__));

except for any of the symbol look-up issues. So, if you want to get the parent of nested function, you can just do

    __traits(parent, __traits(parent, {}))

I'd still probably get the symbol for the parent function inside the
function and create an alias to it which the nested function could use
rather than looking it up in the nested function, because it requires only a
single trait instead of two, but this seems like a cleaner approach to me
than using mixin(__FUNCTION__) - especially since now that I think about it,
you could actually get the wrong function with mixin(__FUNCTION__) if the
function is overloaded - in that case, you'd need
__traits(getOverloads, ...), and you'd need to somehow know which the
correct overload was, which seems like it would be very error-prone.

- Jonathan M Davis