Proposal: user defined attributes

Piotr Szturmaj bncrbme at jadamspam.pl
Fri Mar 16 08:21:41 PDT 2012


Adam D. Ruppe wrote:
> On the ride over here today, I had a thought that
> I think neatly solves the user defined attribute
> question.
>
> enum Serializable { yes, no }
>
> @note(Serializable.yes) int a;

This is just enum. If you use struct or class attributes (like in C#) 
then direct @Struct(constructor args..) might be better.

Moreover, structs and classes may have special member which validates 
attribute target:

struct MyAttribute
{
     template canAttach(alias Symbol)
     {
         // attribute is only valid on structs and
         // may be used only once per symbol
         enum canAttach = is(Symbol == struct) &&
                          !__traits(hasNotes, Symbol);
     }
}

It should be automatically evaluated by the compiler after attribute is 
attached.

Alternatively it may be written like this:

template validate(alias Symbol)
{
     static assert(is(Symbol == struct), "MyAttribute must be used with 
structs");
}

> We introduce two new things to the language:
>
> 1) the @note(expression) attribute. You can put
> as many "notes" on a declaration as you want by
> simply listing them.
>
> The expression inside is appended to a list on
> the declaration.
>
> This would be valid on variables, functions,
> function parameters, struct members, etc.
>
> 2) __traits(getNotes, decl). This returns a tuple
> of all the note expressions.
>
> foreach(i, exp; __traits(getNotes, a)) {
> static assert(is(typeof(exp) == Serializable);
> static assert(exp == Serializable.yes);
> }

This is nice. Also it's base for library functions like hasNotes or 
getNotes!(Symbol, MyAttribute).

> This simple extension to the language enables libraries,
> using existing traits to navigate symbols, to get
> additional information about things and implement it
> however.
>
> The lack of user defined attributes is D's biggest missed
> opportunity right now, and I think this simple proposal
> will plug that hole.

Yes, it's big drawback for serialization and data binding code.

> Previous user-defined attribute proposals have had counter
> arguments like these:
>
> 1) how do you define what is and is not a valid attribute?
>
> Here, the answer is pretty simple: you can put whatever notes
> you want on the thing. Whether the library uses it or not
> is up to it.
>
> It has to be a valid type - so the compiler will catch
> typos and whatnot - but it doesn't have to be used unless
> you ask for it.

It should be any user-defined type that may be used at compile-time. For 
example @UUID("...") should be available out of the box.

> 2) OK, how do you namespace things so different libraries don't
> get different results?
>
> That's where the beauty of the expression type comes in: D
> already has namespaces. foo.Serializable != bar.Serializable,
> so there's no conflict.
>
> We simply declare types. The enum X {yes, no} pattern is already
> common in Phobos, and is also the best way to express a bool condition
> here. (Technically, @note(true) would compile, but it'd be much less
> useful than declaring a name for the note too, with an enum.)
>
> Name conflicts is a problem already solved by the language.

Yes, it should be possible to write @std.UUID("").

> 3) Can we have shared attributes, with declared names so people
> know what to use in their own libraries?

Of course, for example consider a validating attribute "Flags":

@Flags
enum SomeFlags
{
     a = 1,
     b = 2,
     c = 4,
     d = 8
}

During attachment it would check if enum member's bits don't overlap.


More information about the Digitalmars-d mailing list