Thread overview
UDA status
Mar 11, 2013
simendsjo
Mar 11, 2013
simendsjo
Mar 17, 2013
Jacob Carlborg
Mar 17, 2013
simendsjo
March 11, 2013
I've been trying UDAs today, but I'm hitting roadblocks all the time..
For instance:
    @(10) struct A;
    pragma(msg, __traits(getAttributes, A)); // Empty
    @(10) struct B {}
    pragma(msg, __traits(getAttributes, B)); // tuple(10)

I've encountered several other things that has been difficult, especially when combining values and types and trying to manipulate these (might be some Tuple related stuff I'm not getting though).

Are there many outstanding issues regarding UDAs? Many fixes in 2.063?
I cannot find many tickets regarding UDAs in bugzilla.

Seems std.traits isn't updated for UDAs either.

So what's the status of UDAs? Anyone have experience using them yet?
March 11, 2013
On Monday, 11 March 2013 at 19:03:49 UTC, simendsjo wrote:
> I've been trying UDAs today, but I'm hitting roadblocks all the time..
> For instance:
>     @(10) struct A;
>     pragma(msg, __traits(getAttributes, A)); // Empty
>     @(10) struct B {}
>     pragma(msg, __traits(getAttributes, B)); // tuple(10)
>
> I've encountered several other things that has been difficult, especially when combining values and types and trying to manipulate these (might be some Tuple related stuff I'm not getting though).
>
> Are there many outstanding issues regarding UDAs? Many fixes in 2.063?
> I cannot find many tickets regarding UDAs in bugzilla.
>
> Seems std.traits isn't updated for UDAs either.
>
> So what's the status of UDAs? Anyone have experience using them yet?

Some update.. Using a custom Tuple(T...) makes things a bit smoother. Here's my first working test with two templates: hasAttr to see if an attribute exists, and attrOfType to get all attributes matching a type (not sure if I should include values..)

module uda;
debug(UDA) import std.stdio;

template attrOfType(alias OfType, alias Source)
{
    alias _attrOfType!(OfType, AttributeTuple!Source) attrOfType;
}

template hasAttr(alias S, alias A)
{
    bool _hasAttr()
    {
        version(none)
        {
            debug(UDA) pragma(msg, "hasAttr(", TypeOf!S, ", ", A, ")");
            debug(UDA) pragma(msg, "  attributes: ", __traits(getAttributes, TypeOf!S));
        }
        foreach(attr; __traits(getAttributes, TypeOf!S)) {
            static if(isSameAttribute!(attr, A))
                return true;
        }
        return false;
    }
    enum hasAttr = _hasAttr();
}
unittest
{
    struct A1 { int i; }

    struct NoAttr {}
    assert(!hasAttr!(NoAttr, A1));
    NoAttr noAttr;
    assert(!hasAttr!(noAttr, A1));

    @A1
    struct AttrType {}
    assert( hasAttr!(AttrType, A1));
    AttrType attrType;
    assert( hasAttr!(attrType, A1));

    @A1(10)
    struct AttrValue {}
    assert( hasAttr!(AttrValue, A1(10)));
    assert(!hasAttr!(AttrValue, A1(0)));
    assert(!hasAttr!(AttrValue, A1));
    AttrValue attrValue;
    assert( hasAttr!(attrValue, A1(10)));
    assert(!hasAttr!(attrValue, A1(0)));
    assert(!hasAttr!(attrValue, A1));

    @(10) struct AttrPrimitive {}
    assert( hasAttr!(AttrPrimitive, 10));
}

////////////////////////////////////////////
////////////////////////////////////////////
///
///             PRIVATE
///
////////////////////////////////////////////
////////////////////////////////////////////
private:
template isInstanceOrLiteral(alias S)
{
    enum isInstanceOrLiteral = __traits(compiles, typeof(S));
}
template isInstanceOrLiteral(T)
{
    enum isInstanceOrLiteral = false;
}
unittest
{
    assert(!isInstanceOrLiteral!int);
    int i;
    assert( isInstanceOrLiteral!i);
    assert( isInstanceOrLiteral!10);

    struct S {}
    assert(!isInstanceOrLiteral!S);
    S s;
    assert( isInstanceOrLiteral!s);

    class C {}
    assert(!isInstanceOrLiteral!C);
    C c;
    assert(isInstanceOrLiteral!c);
}

template TypeOf(alias S)
{
    static if(isInstanceOrLiteral!S)
        alias typeof(S) TypeOf;
    else
        alias S TypeOf;
}
unittest
{
    struct S {}
    assert( is(TypeOf!S == S));
    S s;
    assert( is(TypeOf!s == S));
}


template Tuple(T...)
{
    alias T Tuple;
}

template AttributeTuple(alias T)
{
    alias Tuple!(__traits(getAttributes, T)) AttributeTuple;
}
unittest
{
    struct NoAttrs {}
    assert( AttributeTuple!(NoAttrs).length == 0);

    struct A1 {}
    @A1 struct S1 {}
    assert( AttributeTuple!(S1).length == 1);
    assert( is(AttributeTuple!(S1)[0] == A1));

    @(10, "aoeu", A1) struct S2 {}
    assert( AttributeTuple!(S2).length == 3);
    assert( AttributeTuple!(S2)[0] == 10);
    assert( AttributeTuple!(S2)[1] == "aoeu");
    assert( is(AttributeTuple!(S2)[2] == A1));

    struct A2 { int i; }
    @A2 @A2(10) struct S3 {}
    assert( AttributeTuple!(S3).length == 2);
    assert( is(AttributeTuple!(S3)[0] == A2));
    assert(!is(AttributeTuple!(S3)[1] == A2)); // static type - not equal
    assert( AttributeTuple!(S3)[1] == A2(10));
}

template isSameAttribute(alias A, alias B)
{
    static if(isInstanceOrLiteral!A && isInstanceOrLiteral!B)
        static if(__traits(compiles, A == B))
            enum isSameAttribute = A == B;
        else
            enum isSameAttribute = false;
    else static if(!isInstanceOrLiteral!A && !isInstanceOrLiteral!B && is(A == B))
        enum isSameAttribute = true;
    else
        enum isSameAttribute = false;
}
template isSameAttribute(A, B)
{
    enum isSameAttribute = is(A == B);
}
template isSameAttribute(alias A, B)
{
    enum isSameAttribute = false;
}
template isSameAttribute(A, alias B)
{
    enum isSameAttribute = false;
}
unittest
{
    assert( isSameAttribute!(1, 1));
    assert(!isSameAttribute!(1, 2));
    assert( isSameAttribute!("aoeu", "aoeu"));
    assert(!isSameAttribute!("aoeu", "qwerty"));
    assert( isSameAttribute!(int, int));
    assert(!isSameAttribute!(int, uint));
    assert(!isSameAttribute!(int, 1));
    assert(!isSameAttribute!(1, int));
    struct S {int i;}
    assert(!isSameAttribute!(S(1), 1));
    assert( isSameAttribute!(S(1), S(1)));
}

private template _attrOfType(alias OfType, Attrs...)
{
    static if(Attrs.length == 0)
    {
        alias Tuple!() _attrOfType;
    }
    else static if(Attrs.length == 1)
    {
        static if(isSameAttribute!(Attrs[0], OfType))
            alias Tuple!(Attrs[0]) _attrOfType;
        else
            alias Tuple!() _attrOfType;
    }
    else
    {
        alias _attrOfType!(OfType, Attrs[1..$]) Rest;
        static if(isSameAttribute!(Attrs[0], OfType))
            alias Tuple!(Attrs[0], Rest) _attrOfType;
        else
            alias Tuple!(Rest) _attrOfType;
    }
}
unittest
{
    struct A1 { int i; }
    @(1, A1, A1(1), A1(2)) struct S1 {}
    assert(attrOfType!(2, S1).length == 0);
    assert(attrOfType!(1, S1).length == 1);
    assert(attrOfType!(1, S1)[0] == 1);
    assert(attrOfType!(A1, S1).length == 1);
    assert(is(attrOfType!(A1, S1)[0] == A1));
    assert(attrOfType!(A1(1), S1).length == 1);
    assert(attrOfType!(A1(1), S1)[0] == A1(1));
    assert(attrOfType!(A1(2), S1).length == 1);
    assert(attrOfType!(A1(2), S1)[0] == A1(2));
}
March 17, 2013
On 2013-03-11 21:41, simendsjo wrote:

> Some update.. Using a custom Tuple(T...) makes things a bit smoother.
> Here's my first working test with two templates: hasAttr to see if an
> attribute exists, and attrOfType to get all attributes matching a type
> (not sure if I should include values..)

You need to use TypeTuple and not Tuple. This is my library functions for UDA's:

https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d

-- 
/Jacob Carlborg
March 17, 2013
On Sunday, 17 March 2013 at 14:46:59 UTC, Jacob Carlborg wrote:
> On 2013-03-11 21:41, simendsjo wrote:
>
>> Some update.. Using a custom Tuple(T...) makes things a bit smoother.
>> Here's my first working test with two templates: hasAttr to see if an
>> attribute exists, and attrOfType to get all attributes matching a type
>> (not sure if I should include values..)
>
> You need to use TypeTuple and not Tuple. This is my library functions for UDA's:
>
> https://github.com/jacob-carlborg/orange/blob/master/orange/core/Attribute.d

Thanks. I've gotten quite far already:

    struct A { int i; }
    @("struct S")
    struct S {
        @("int i", 0, 1, S, A(-1))
        int i;
        @("string a", "aoeu", 2, string, A(10))
        string a;
        @("long f(int i)")
        long f(int i) { return i; }
    }
    alias TypeTuple!(  TupleWrapper!(S, "struct S")
                     , TupleWrapper!(S.i, "int i", 0, 1, S, A(-1))
                     , TupleWrapper!(S.a, "string a", "aoeu", 2, string, A(10))
                     , TupleWrapper!(S.f, "long f(int i)")
                     ) Expected;
    alias getMembersAndAttributes!S Actual;
    static assert(isEqual!(TupleWrapper!Expected, TupleWrapper!Actual));