Custom attributes (again)

Ary Manzana ary at esperanto.org.ar
Fri Apr 6 03:27:52 PDT 2012


On 4/6/12 6:12 PM, Walter Bright wrote:
> On 4/6/2012 2:50 AM, Ary Manzana wrote:
>> The syntax in Java for declaring an attribute:
>>
>> public @interface Foo {
>> String xxx;
>> int yyy;
>> }
>>
>> In D maybe @interface could be used to (in order to avoid introducing
>> another
>> keyword... or maybe use @attribute instead):
>>
>> @attribute Foo {
>> string xxx;
>> int yyy;
>> }
>
> I don't see the need for creating a new kind of symbol.
>
>
>> 2. You use them by using their names. What you are proposing if for
>> attribute
>> foo to be @attr(foo). But in Java it's @foo.
>>
>> So in Java you would use that attribute like this:
>>
>> @Foo(xxx = "hello", yyy = 1);
>> void func() {}
>>
>> Then you can get the "Foo" attribute in func, and ask for it's xxx and
>> yyy.
>
> This is a runtime system.

Yes, but I'm thinking about a compile-time system (as I showed in the 
example usages below).

>
>
>> Now, your proposal is much simpler and it will become inconvenient in
>> some
>> cases. For example suppose you want to provide attributes for
>> serialization (I
>> guess the classic example). With your proposal it would be:
>>
>> /// This is actually an attribute. Use this together with
>> serialized_name.
>> enum serialize = 1;
>> enum serialized_name = 2;
>>
>> @attr(serialize = true, serialized_name = "Foo")
>> int x;
>
> No, it would be:
>
> enum serialize = true;
> enum serialize_name = "Foo";
> @attr(serialize, serialized_name) int x;
>
> There would be no initialization in the @attr syntax.

Hmmm... I didn't get that quite well. You are using the symbol's name as 
the attribute name? In my example I missed splitting it into two files:

my_attributes.d:

@attribute serialize { }

my_usage_of_it.d:

import my_attributes;

@serialize(...)


>
>> Now, with the way things are done in Java and C#:
>>
>> /// Marks a field to be serialized.
>> @attribute serialize {
>> /// The name to be used.
>> /// If not specified, the name of the member will be used instead.
>> string name;
>> }
>>
>> @serialize(name = "Foo")
>> int x;
>>
>> You can see the syntax is much cleaner. The attribute declaration also
>> serves as
>> documentation and to group attributes related to the serialization
>> process.
>
> I don't see that it is cleaner - there's no particular reason why a new
> symbol type needs to be introduced.
>
>>
>> Now, to implement this is not very much difficult than what you proposed.
>>
>> 1. Introduce the syntax to define attributes. Piece of cake, since
>> it's much
>> more or less the syntax of a struct, but functions or nested types are
>> not
>> allowed. Parse them into an AttributeDecl or something like that.
>> 2. When the compiler finds @attr(field = value) it uses normal lookup
>> rules to
>> find "attr". Then it checks it's an attributes. Then all fields are
>> check in
>> turn to see if their type match. You can probably put there anything
>> that's
>> compile-time evaluatable, though usually primitive types and strings
>> are enough.
>> If a field is not specified, it's type.init will be used.
>> 3. The syntax for querying is almost the same as you proposed:
>>
>> __traits(hasAttribute, x, serializable) // true
>> __traits(getAttribtue, x, serializable, name) // "Foo"
>>
>> 4. Declare the core attributes in object.di or similar: @safe,
>> @nothrow, etc.
>> You can also document them.
>> 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute
>> can be used
>> for that.
>
> @safe, @nothrow, etc., require a lot of semantic support in the
> compiler. They cannot pretend to be user defined attributes.

Yes they can. That's how it is done in C# and Java. In fact, IUnknown is 
pretending to be an interface and has semantic support in the compiler.


More information about the Digitalmars-d mailing list