Thread overview
proper way to find if attribute present?
Oct 24, 2013
Daniel Davidson
Oct 24, 2013
Jonathan M Davis
Oct 24, 2013
Adam D. Ruppe
Oct 24, 2013
Dicebot
Oct 24, 2013
Adam D. Ruppe
October 24, 2013
enum Bar = "Bar";
@("Foo") @Bar int x;
pragma(msg, __traits(getAttributes, x));

This prints: tuple("Foo", "Bar")

How do you run code only if "Bar" is associated with a symbol like x?
I was hoping something like this:
pragma(msg, hasAnnotation!(x, Bar));

Where getAnnotation from (http://forum.dlang.org/thread/jxbdiwyyxwnmmybiqvyq@forum.dlang.org)
was written as:

template hasAnnotation(alias f, Attr) {
  bool helper() {
    foreach(attr; __traits(getAttributes, f))
      static if(is(attr == Attr) || is(typeof(attr) == Attr))
        return true;
    return false;

  }
  enum bool hasAnnotation = helper;
}


I am missing how this can be used.

Thanks
Dan
October 24, 2013
On Thursday, October 24, 2013 18:22:43 Daniel Davidson wrote:
> enum Bar = "Bar";
> @("Foo") @Bar int x;
> pragma(msg, __traits(getAttributes, x));
> 
> This prints: tuple("Foo", "Bar")
> 
> How do you run code only if "Bar" is associated with a symbol
> like x?
> I was hoping something like this:
> pragma(msg, hasAnnotation!(x, Bar));

You should probably use std.traits.functionAttributes:

http://dlang.org/phobos/std_traits.html#.FunctionAttribute

And in general, you should favor using std.traits over __traits. Ideally, no code outside of the standard library would need to use __traits. That's not currently the case unfortunately, but it is the case that std.traits has much of what you need for anything involving static introspection.

- Jonathan M Davis
October 24, 2013
On Thursday, 24 October 2013 at 17:36:42 UTC, Jonathan M Davis wrote:
> You should probably use std.traits.functionAttributes:

it doesn't list UDAs though.
October 24, 2013
I use this small helper in vibe.d:

=======================
template extractUda(UDA, alias Symbol)
{
    import std.typetuple : TypeTuple;

    private alias TypeTuple!(__traits(getAttributes, Symbol)) udaTuple;

    private template extract(list...)
    {
        static if (!list.length)
            enum extract = null;
        else {
            static assert (!is(list[0] == UDA), "extractUda is designed to look up values, not types");

            static if (is(typeof(list[0]) == UDA))
                enum extract = list[0];
            else
                enum extract = extract!(list[1..$]);
        }
    }

    enum extractUda = extract!udaTuple;
}
=======================

Used like this:
=======================
@Bar("value") void foo();

enum uda = extractUda!(Bar, foo);

static if (is(typeof(uda) != typeof(null)))
    static assert (uda == Bar("value"));
=======================

It is far from perfection but can serve as a starting point for more complete implementation (though I have kept certain limitations intentionally)
October 24, 2013
On Thursday, 24 October 2013 at 16:22:44 UTC, Daniel Davidson wrote:
> template hasAnnotation(alias f, Attr) {

This function looks for annotations as identified by type. Instead of using a plain string, you should make them some kind of struct:

struct MyAnnotation {
   string value;
}

Then you attach it like this:

@MyAnnotation("some value") void foo() {}

Then you'll be able to get it with the other two functions in there:

static if(hasValueAnnotation!(foo, MyAnnotation)) {
    pragma(msg, getAnnotation!(foo, MyAnnotation)); // prints MyAnnotation("some value")

    // or you can fetch it into a variable:
    MyAnnotation a = getAnnotation!(foo, MyAnnotation);
    assert(a.value == "some value");
}


It is possible to use plain string in place of the MyAnnotation struct:

 @("some value") void foo() {}

static if(hasValueAnnotation!(foo, string)) {
    pragma(msg, getAnnotation!(foo, string)); // prints MyAnnotation("some value")

    // or you can fetch it into a variable:
    string a = getAnnotation!(foo, string);
    assert(a == "some value");
}


But that isn't as reliable across modules because strings might be reused by anyone. A struct would always have a unique identifier - the struct name, which can be disambiguated by module.