User attributes (was Proposal on improvement to deprecated)

Piotr Szturmaj bncrbme at jadamspam.pl
Mon Oct 3 11:22:02 PDT 2011


Aleksandar Ružičić wrote:
> What about using an attribute for that?

Looks like a good use case for user defined attributes (I need to write
DIP on that).

struct Deprecated
{
     string message;

     // instantiated on every symbol marked with this attribute
     template applyAttribute(Symbol)
     {
         static assert(0, Symbol.stringof ~ "is deprecated: " ~ message);
     }
}

@std.attributes.Deprecated("test");
class A
{
}

This is just enough for deprecation. For other cases __traits should be
extended with hasAttribute and getAttributes:

static assert(__traits(hasAttribute, A, Deprecated));
static assert(is(__traits(getAttributes, A) == TypeTuple!(Deprecated)));

// struct Deprecated available at compile time
static assert(__traits(getAttribute, A, 0).message != "");

----
Serialization example:
----

@std.xml.XmlElement("address")
struct Address
{
     string street;
     string city;
     string country;
}

@std.xml.XmlElement("person")
struct Person
{
     @XmlAttribute("age")
     int ageInYears;
     string fullName;
     @XmlElement("addr") // override element name
     Address address;
}

// with Uniform Function Call Syntax:

void save(T)(T serializable, string fileName)
     if (__traits(hasAttribute, T, std.xml.XmlElement))
{
     auto elemAttr = __traits(getAttribute, T, std.xml.XmlElement);
     // serialization code
}

auto person = Person(30, "John Doe");
person.address = Address("Some street address", "London", "UK");
person.save("person.xml");

// should produce this content:

<?xml version="1.0" encoding="UTF-8" ?>
<person age="30">
     <fullName>John Doe</fullName>
     <addr>
         <street>Some street address</street>
         <city>London</city>
         <country>UK</country>
     </addr>
</person>

----
Other example with UFCS (flag handling)
----

struct Flags
{
     template applyAttribute(Symbol)
     {
	// 1. test if Symbol is an enum
         // 2. test if there is only one @Flags attribute for this enum
         // 3. test if flags don't overlap
     }
}

@Flags
enum A
{
     Flag1 = 1,
     Flag2 = 2,
     Flag3 = 4
}

bool hasFlag(T, V)(T t, V v)
     if (__traits(hasAttribute, T, Flags))
{
     return t & v == v;
}

void f(A a)
{
     if (a.hasFlag(A.Flag1))
     {
         //
     }
}

There are of course many other possible use cases like Object/Relational
Mapping, RPC/Remoting, debugger visualization overrides, hints for the
GC, etc.

User defined attributes provide a powerful way to extend language
without constantly upgrading the compiler (and avoiding "too many
features" in it).

I would love to hear any opinions about general idea of user defined
attributes in D, not necessarily this particular syntax as it is only
my loud thinking, though it should show what the whole thing is about.


More information about the Digitalmars-d mailing list