www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using getSymbolsByUDA in a static foreach loop

reply Jack Stouffer <jack jackstouffer.com> writes:
I'm trying to use getSymbolsByUDA in order to loop over all of 
the members in a struct with a certain UDA, and then call a 
function on the member. The plan is to use this to avoid looping 
over an array of function pointers.

However, the compiler is giving a strange error and the 
documentation of getSymbolsByUDA is unhelpful, as there are no 
practical use-case examples.

Here's a very simplified version of my code

```d
import std.traits;

enum Runnable;

struct SubSystem
{
     void run();
}

struct Manager
{
      Runnable SubSystem subsystem;

     void run()
     {
         static foreach(system; getSymbolsByUDA!(Manager, 
Runnable))
         {
             system.run();
         }
     }
}

void main()
{
     Manager m;
     m.run();
}

```

Result:

```
onlineapp.d(16): Error: value of `this` is not known at compile 
time
```

This seems to me to be the logical way to write this code. What 
am I missing?
Jan 19 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 19 January 2022 at 20:46:17 UTC, Jack Stouffer 
wrote:
         static foreach(system; getSymbolsByUDA!(Manager, 
 Runnable))
         {
             system.run();
 onlineapp.d(16): Error: value of `this` is not known at compile 
 time
The getSymbols returns aliases, meaning you hit what I wrote about a few days ago: http://dpldocs.info/this-week-in-d/Blog.Posted_2022_01_10.html#tip-of-the-week The `this` is a runtime value and all the other `static` things work on compile time info. So you want to `__traits(child, system, this).run()` and it should work - the traits child will re-attach a this value.
Jan 19 2022
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 19 January 2022 at 20:53:29 UTC, Adam D Ruppe wrote:
 So you want to `__traits(child, system, this).run()` and it 
 should work - the traits child will re-attach a this value.
The error is actually coming from trying to use the result of getSymbolsByUDA in the right part of the `static foreach`, not the call to the `run` function. Which was odd to me because I thought it just returned a `AliasSeq`. Here's a link to the erroring code with your traits change: https://run.dlang.io/is/gO84ox
Jan 19 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 19 January 2022 at 21:44:57 UTC, Jack Stouffer 
wrote:
 The error is actually coming from trying to use the result of 
 getSymbolsByUDA in the right part of the `static foreach`
huh...... I never use most of std.traits, they just complicate things. Bleh idk, I wouldn't bother with it and loop through the __traits instead.
Jan 19 2022
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 19 January 2022 at 21:49:12 UTC, Adam D Ruppe wrote:
 I never use most of std.traits, they just complicate things. 
 Bleh idk, I wouldn't bother with it and loop through the 
 __traits instead.
Unless I'm missing something obvious this has to be a DMD bug, because this prints nothing: ```d import std.traits; import std.stdio; enum Runnable; struct SubSystem { void run() { writeln("SubSystem ran"); } } struct Manager { Runnable SubSystem subsystem; void run() { static foreach(member; __traits(allMembers, Manager)) { static foreach (attribute; __traits(getAttributes, member)) { static if (attribute == Runnable) { __traits(child, Manager, member).run(); } } } } } void main() { Manager m; m.run(); } ``` The `__traits(getAttributes, member)` call always returns an empty tuple. Calling `__traits(getAttributes, Manager.subsystem)` manually works as expected.
Jan 19 2022
parent reply Adam Ruppe <destructionator gmail.com> writes:
On Thursday, 20 January 2022 at 00:55:33 UTC, Jack Stouffer wrote:
             static foreach(member; __traits(allMembers, 
 Manager))
member here is a string, not the member. I prefer to call it memberName. Then you __traits(getMember, Manager, memberName) to actually get the alias you can pass to getAttributes.
Jan 19 2022
parent Jack Stouffer <jack jackstouffer.com> writes:
On Thursday, 20 January 2022 at 01:14:51 UTC, Adam Ruppe wrote:
 On Thursday, 20 January 2022 at 00:55:33 UTC, Jack Stouffer 
 wrote:
             static foreach(member; __traits(allMembers, 
 Manager))
member here is a string, not the member. I prefer to call it memberName. Then you __traits(getMember, Manager, memberName) to actually get the alias you can pass to getAttributes.
Thanks, that fixed it. Final working version for anyone who finds this thread: ```d import std.traits; import std.stdio; enum Runnable; struct SubSystem { void run() { writeln("SubSystem ran"); } } struct Manager { Runnable SubSystem subsystem; void run() { static foreach(memberName; __traits(allMembers, Manager)) { static foreach (attribute; __traits(getAttributes, __traits(getMember, Manager, memberName))) { static if (is(attribute == Runnable)) { __traits(getMember, Manager, memberName).run(); } } } } } void main() { Manager m; m.run(); } ```
Jan 19 2022