custom attribute proposal (yeah, another one)

Steven Schveighoffer schveiguy at yahoo.com
Fri Apr 6 06:23:01 PDT 2012


OK, so I woke up this morning to find a huge discussion on attributes, and  
I'd like to once again propose the idea of how to define and use an  
attribute.

I do not like the idea of:

@attr(identifier)

Why?  Because what the hell did we create that "@" syntax for?  I though  
it was to avoid misinterpreting such things as normal symbols, and avoid  
creating new keywords.  Why should the compiler be the only one able to  
use such symbols?

Another thing I don't like is some idea that only a certain type of  
construct can be the identifier.  An attribute should have one requirement  
-- that it can be created/determined at compile time.

So here is my proposal:

1. Introduce a new compiler-defined attribute @attribute (or @attr or  
something better, the name isn't important).
2. This attribute can *only* be used on a module-level function.
3. @attribute functions *must* be CTFE-able.
4. An @attribute function can be used as a user-defined attribute on any  
declaration using the syntax @identifier where identifier is the name of  
the attribute function (subject to normal function lookup rules).  If the  
attribute can be called without parameters, the parentheses are optional.
5. When used on a declaration, that CTFE function is called during  
compile-time, and the result of that function is stored as metadata on  
that symbol.  It does not affect the type of the symbol or transfer to any  
other symbols that are assigned to the value of that declaration (in other  
words, it *cannot* be used as a type constructor).
6. The metadata is stored in a key-value pair, with the key being the  
symbol of the @attribute function, and the value being the result of the  
CTFE function.
7. One can lookup whether an attribute exists on a symbol using  
__traits(hasAttribute, symbol).
8. One can retrieve the value of the CTFE result using  
__traits(getAttribute, symbol).  If the CTFE function returns void, this  
is a compiler error.

And that's it.  We can extend this eventually to storing something in  
TypeInfo, but I'm not sure we need that.  However, I want to stress that  
having runtime type metadata is not a requirement for this proposal.

Example usage:

@attribute bool serializable(bool yesorno = true) { return yesorno; }

unittest {
    // serializable is a normal function also
    assert(serializable() == true);
    assert(serializable(true) == true);
    assert(serializable(false) == false);
}

@serializable struct MyType
{
    int x;
    int y;
    @serializable(false) int z;
}

string serialize(T)(const ref T t) if (__traits(hasAttribute,  
serializable) && __traits(getAttribute, serializable))
{
   // serialize each field.  Skip any fields that are marked as  
serializable == false
}

-Steve


More information about the Digitalmars-d mailing list