User defined attributes use

simendsjo simendsjo at gmail.com
Mon Sep 16 00:36:09 PDT 2013


On Monday, 16 September 2013 at 06:47:40 UTC, ilya-stromberg 
wrote:
> On Sunday, 15 September 2013 at 18:31:40 UTC, simendsjo wrote:
>> On Sunday, 15 September 2013 at 17:34:06 UTC, matovitch wrote:
>>> Hi everyone,
>>>
>>> I read the documentation about user defined attributes, but I 
>>> don't see their uses. Ok, it'a a template expression you can 
>>> link to a declaration, but what are they useful for ? (not 
>>> sure about the syntax ;-))
>>>
>>> Can you declare a template constraint as a user defined 
>>> attribute to do something like :
>>>
>>> void 
>>> template_function_which_go_back_and_forth(@("Bidirectional") 
>>> @("Range") BR)(BR br) {...}
>>>
>>> This would be awesome (even if not really occidental) to do 
>>> something like:
>>>
>>> @("SmallTypeSet") @("MediumTypeSet") @("LargeTypeSet") Type
>>>
>>> This could allow to build tree based category structure.
>>
>> It enables declarative programming.
>> And because this is D, there is no runtime overhead.
>> A common use is to add semantics to types and instances that 
>> is difficult or very intrusive to do by creating 
>> structs/classes by hand.
>>
>> A little validation example:
>>
>> @nonNull // An instance shouldn't be allowed to be null
>> class C {
>>  @matches("[0-9]+")
>>  string someNumber;
>>
>>  @interval!"(]"(0, 10) // (0, 10] range
>>  int someInt;
>> }
>>
>> C c;
>> validate(c); // returns ["C is null", "someNumber doesn't 
>> match '[0-9]+'", "someInt is outside the interval '(0, 10]'"]
>>
>> And ORMs usually use annotations:
>>
>> @table("some_tablename")
>> class C {
>>  @id("id_field_name")
>>  int id;
>> }
>>
>> Take a look at C# and Java libraries to see how many uses 
>> attributes/annotations - they are still quite new in D, so 
>> they are still underutilized.
>> A very big difference is of course that UDAs are available at 
>> compile time :)
>
> Can you print a full examle? For example, can you implement 
> "matches" UDA and validate function.
> It's intresting how can I create new UDA and check if it's 
> available for class/field.

I don't have a full example without adding a lot of code, but 
this partial
example might give you the gist of it.


// This is the type that validates
struct matches(string mustMatch)
{
     alias re = ctRegex!(mustMatch);

     static string[] validate(T)(const ref T t)
     {
         static if(!isSomeString!T)
             static assert(0, "matches only works on strings, not 
"~T.stringof);
         return match(t, re).empty ? ["no match"] : null;
     }
}

// and this is the code that runs all validators for a variable
void validate(alias T)(ref Appender!(string[]) app)
{
     static if(isTupleWrapper!T)
     {
         validate!(T.Head)(app);
         validate!(T.Tail)(app);
     }
     else
     {
         foreach(memberAttr; getValidaterAttrs!T)
         {
             foreach(attr; memberAttr.Tail)
             {
                 foreach(msg; attr.validate(T))
                     if(msg.length)
                         app.put(msg);
             }
         }
     }
}

// .. And here is some of the plumbing

string[] validate(Vars...)()
{
     auto app = appender!(string[])();
     validate!Vars(app);
     return app.data();
}


// The getMembersAndAttributesWhere are templates in my little 
library that isn't released. Uses quite some custom __traits 
stuff, but it's basically __traits(getAttributes
template getValidaterAttrs(alias T)
{
     alias getValidaterAttrs = 
TypeTuple!(getMembersAndAttributesWhere!(T, 
isValidationAttr).Elements,
                                          
getMembersAndAttributesWhere!(TypeOf!T, 
isValidationAttr).Elements);
}

// Well.. Incomplete
template isValidationAttr(alias T)
{
     enum isValidationAttr = hasMember!(TypeOf!T, "validate");
}


More information about the Digitalmars-d-learn mailing list