Using getSymbolsByUDA in a static foreach loop
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?
Re: Using getSymbolsByUDA in a static foreach loop
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.
Re: Using getSymbolsByUDA in a static foreach loop
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
Re: Using getSymbolsByUDA in a static foreach loop
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.
Re: Using getSymbolsByUDA in a static foreach loop
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.
Re: Using getSymbolsByUDA in a static foreach loop
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.
Re: Using getSymbolsByUDA in a static foreach loop
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(); } ```