On Friday, 14 February 2020 at 22:24:14 UTC, Ben Jones wrote:
Hi all,
I'm getting unexpected results while trying to process symbols
from a module, some of which are enums.
Depending on whether or not I comment out the first static
foreach loop below, fullyQualifiedName gives me different
results in the second loop.
In either case, I'm surprised I can't grab the UDAs in the
second static foreach loop. Any ideas what's going on?
Test case:
---a.d---
module a;
@Object
enum x = "hello";
@Object
enum y = "goodbye";
@Object
struct z{}
---main.d---
template symbols(alias Mod){
import std.meta;
alias toSymbol(alias T) = __traits(getMember, Mod, T);
alias symbols = staticMap!(toSymbol, __traits(allMembers,
Mod));
}
void main(){
import std.traits;
import std.meta;
import a;
//commenting this out changes the results below
static foreach(sym; symbols!a){
pragma(msg, fullyQualifiedName!sym);
pragma(msg, __traits(getAttributes, sym));
}
pragma(msg, "\nget with UDAs\n");
pragma(msg, getSymbolsByUDA!(a, Object));
alias udaSyms = getSymbolsByUDA!(a, Object);
pragma(msg, staticMap!(fullyQualifiedName, udaSyms));
static foreach(us; udaSyms){
pragma(msg, fullyQualifiedName!us);
pragma(msg, __traits(getAttributes, us));
}
}
---
annotated output of dmd main.d:
with the first loop commented out:
get with UDAs
tuple("hello", "goodbye", (z))
tuple("a.x", "a.y", "a.z")
a.x
tuple() //why is the UDA gone?
a.y
tuple()
a.z
tuple((Object))
and with the first loop:
object
tuple()
main.main.sym //it's not a.x anymore, it's the name of the
local var for static foreach?
tuple()
main.main.sym
tuple()
a.z
tuple((Object))
get with UDAs
tuple("hello", "goodbye", (z))
tuple("main.main.sym", "main.main.sym", "a.z") //and the
results are changed here too?
main.main.sym
tuple()
main.main.sym
tuple()
a.z
tuple((Object))
From language spec [1]: "the name of the static foreach variable
is bound to the i-th entry of the sequence, either as an enum
variable declaration (for constants) or an alias declaration (for
symbols).
Enums are treated differently, so your 'sym' is not an alias to
the original enum but an enum itself with the same value. Because
of that, fullyQualifiedName or any template with alias argument
will just get the sym temporary not the enum from the symbols
tuple.
This code should work:
static foreach(i, _; symbols!a){
pragma(msg, fullyQualifiedName!(symbols!a[i]));
// or manually aliased, but you need to use regular
foreach or {{ }} to avoid redefinitions.
alias sym = symbols!a[i];
pragma(msg, fullyQualifiedName!sym);
}
[1] https://dlang.org/spec/version.html#staticforeach