www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Trying to understand something about UDAs.

reply Kevin Balbas <kbalbas hotmail.com> writes:
I'm trying to figure out how to test whether a UDA struct was 
initialized with arguments (and change the behavior of the 
surrounding code if it was.  While I was tinkering around with 
test files, I came up with this little gem:

import std.traits;

struct Attr
{
     string str;
}

 Attr("test")
void foo(){}

 Attr
void bar(){}

void main()
{
     alias UDA = getUDAs!(bar, Attr)[0];
     static if (__traits(hasMember, UDA, "str"))
     {
         static if (__traits(compiles, __traits(getMember, UDA, 
"str")))
         {
             __traits(getMember, UDA, "str"); // Compile error! 
need 'this' for 'str' of type 'string'
         }
     }
}

I can rationalize what the error means -- the compiler wasn't 
given a string so it requires a concrete object to get the member 
from.  What I don't understand is why *both* of those static ifs 
passed.  If it has the member and I can't get it, and if getting 
the member compiles yet at the same time it doesn't, I'm not sure 
how I can actually make this test work.

It would make sense if the attribute over bar wasn't semantically 
valid, but I can use it in every other way *except* getting the 
string field out of it.

Am I missing something obvious here?
Dec 12 2016
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 12 December 2016 at 19:37:42 UTC, Kevin Balbas wrote:
 I'm trying to figure out how to test whether a UDA struct was 
 initialized with arguments (and change the behavior of the 
 surrounding code if it was.
Easy solution: test the type. Attr is setting the type as a UDA, Attr("test") is setting a *value* of type Attr. static if(is(UDA)) { // UDA is a type, so it was UDA } else { // it is something else (do further tests to see if value, etc). For example, test is(typeof(UDA) == Attr) to see if it is a value of type Attr. }
 I can rationalize what the error means -- the compiler wasn't 
 given a string so it requires a concrete object to get the 
 member from.  What I don't understand is why *both* of those 
 static ifs passed.  If it has the member and I can't get it, 
 and if getting the member compiles yet at the same time it 
 doesn't, I'm not sure how I can actually make this test work.
So you can get the member of a type, but not the value of that member. getMember itself succeeds - you can pass the result to further reflection things (test its type, offset, etc.), but you cannot get the value, which is what your code was trying to do there (that is like if you wrote `"foo";` in the middle of nowhere. It treats the string as an orphaned value). Basically, getMember is legal, just not in the context you were trying it, thus the __traits(compiles) works but the next line doesn't. But the static if(is(UDA)) is probably what you actually want.
Dec 12 2016
parent Kevin Balbas <kbalbas hotmail.com> writes:
On Monday, 12 December 2016 at 19:56:27 UTC, Adam D. Ruppe wrote:
 But the static if(is(UDA)) is probably what you actually want.
That's exactly what I was looking for, thanks. I'm not sure I ever would've figured out that one on my own.
Dec 12 2016