April 08, 2012
I don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.

1. Attributes add meta data baggage to a symbol
2. This meta data is thought of as a read-only hash (has, get, iterate)
3. Can be queried at compile-time
4. The syntax is concise (i.e. improves over implementing attributes 'manually' with mixins)

Now the compiler has solved things (what is a symbol, an AST, ...) in one specific way and to keep it stable and the amount of work within bounds, any implementation details of attributes that make invasive changes necessary should be postponed. I don't know the compiler, so it is just my gut feeling when I say that annotating local variables could be a refinement to 1) that doesn't work well. You get the point.

With that in mind it would be good to know exactly what can simply be tacked onto the front-end (rather than refactoring a complex part of it). "What do you want to hear?" I hear you ask. Ok, here is my shameless "since D is supposed to be" argument: D is supposed to be pragmatic, so I would start with a collection of use cases. Really, "I want attributes to be like this" is not enough. The use case should be stated in a fashion, that programmers without experience in the field can follow. The standard use cases for attributes are must-haves, the rest can be nice-to-haves.

Add to the list, what you need from the attribute system:

** Serialization/RPC **

A relational SQL database comes with meta information on data types. We want to annotate D types with the corresponding types in the DB. This can be used to validate the value ranges at runtime, generate the correct SQL to work with the tables or even create tables that don't exist already. It is also common to establish relations between tables. The struct Parent may have a 'Child*[]' field and Child a 'Parent*' field.
The same applies to RPC. For example we may want to return a bool[] using a special case in the RPC system for bit arrays: '@Rpc(type = RpcType.native_bit_array, mode = RpcMode.async) bool[] foo() { … }'. This annotation applies to the symbol foo. If make this a more complex return type, it becomes this:

	enum RpcMode …;
	enum RpcType …;

	struct Rpc …;
	struct RpcStruct …;
	// has a single field, syntax options:
	// @RpcTypeMap(type = RpcType.int)
	// @RpcTypeMap(RpcType.int)
	// @RpcTypeMap(int) ?
	struct RpcTypeMod { RpcType type };

	@RpcStruct struct MyRet {
		string name;
		@RpcTypeMap(RpcType.native_bit_array) bool[] flags;
	}

	@Rpc(mode = RpcMode.async) MyRet foo() { … }

For RPC it is also necessary, to annotate parameters in the same way:

	void foo(@RpcTypeMap(RpcType.native_bit_array) bool[] flags) { … }


** Edit object properties in a GUI (as suggested by Manu) **

As seen in GUI builders, often the need occurs to generate bindings to data structures in order to edit their properties in a convenient user interface. A uint field may be edited using a RGB+Alpha color selector and serialized into a data file. The requirements for the annotations are the same as above. (I know that RTTI would make life easier here, but it isn't a show stopper.)



For these to work it would require:
- user annotations to functions/methods/structs/classes
- only CTFE support (as annotations don't change at runtime)
- no influence on language semantics
And I agree with others that it is a good idea to implement annotations as structured types (POD structs at least) to avoid spelling mistakes and encourage IDE support. Just as an idea: Such structs, could contain their own logic. So some annotations which work stand-alone could validate themselves (invariant()?), print debug msgs, write binding definitions to text files (if CTFE I/O happens) or actually mixin code if used on structs/classes. But that's just brain-storming to give an idea why annotations as key/value pairs could be unflexible.
Generally C# and Java annotations have both been a success, so they are both what people mostly expect and a good 'template' for D aside from runtim vs. compile-time issues.

thanks for reading :)

-- 
Marco

April 08, 2012
On 2012-04-08 09:27, Marco Leise wrote:
> I don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.

> For these to work it would require:
> - user annotations to functions/methods/structs/classes
> - only CTFE support (as annotations don't change at runtime)

I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.

-- 
/Jacob Carlborg
April 08, 2012
Am Sun, 08 Apr 2012 12:44:17 +0200
schrieb Jacob Carlborg <doob@me.com>:

> On 2012-04-08 09:27, Marco Leise wrote:
> > I don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.
> 
> > For these to work it would require:
> > - user annotations to functions/methods/structs/classes
> > - only CTFE support (as annotations don't change at runtime)
> 
> I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.
> 

Yeah, it was supposed to mean "it requires CTFE support, runtime support is possible" :)

-- 
Marco

April 09, 2012
Le 08/04/2012 12:44, Jacob Carlborg a écrit :
> On 2012-04-08 09:27, Marco Leise wrote:
>> I don't want this thread to disappear. The ideas presented here have
>> common basic features among the nice-to-haves.
>
>> For these to work it would require:
>> - user annotations to functions/methods/structs/classes
>> - only CTFE support (as annotations don't change at runtime)
>
> I don't see why the attributes should be accessible at runtime. Even if
> they're read-only it's still good to be able to read the attributes at
> runtime.
>

If it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.
April 09, 2012
On 4/6/2012 3:49 AM, Timon Gehr wrote:
> On 04/06/2012 12:23 PM, Walter Bright wrote:
>> On 4/6/2012 2:54 AM, Timon Gehr wrote:
>>> Should add additional information to the type Foo. I don't see any
>>> issues with
>>> it, and not supporting it would be very strange.
>>
>> How would:
>>
>> @attr(foo) int x;
>> int y;
>>
>> work? Are x and y the same type or not?
>
> Yes, they are.
>
> (But a future extension might leave this choice up to 'foo')
>
>> Now, consider:
>>
>> auto c = b ? x : y;
>>
>> What type does c have? int or @attr(foo)int ? And that's really just the
>> beginning. How about:
>>
>> struct S(T) {
>> T t;
>> }
>>
>> Instantiate it with S!int and S!(@attr(foo)int). Are those the same
>> instantiation, or different? If the same, does S.t have the attribute or
>> not?
>
> There is no such thing as an @attr(foo) int, because @attr is not a type
> constructor.

But you said it was added to the *type*.
April 09, 2012
On 4/6/2012 4:20 AM, Manu wrote:
>     On 4/6/2012 2:54 AM, Timon Gehr wrote:
>          Should add additional information to the type Foo.
> Attributes are on the declaration, and not passed around.

Right, they are not added to the *type*.
April 10, 2012
On 2012-04-09 23:49, deadalnix wrote:

> If it is available at compile time, it is implementable at runtime as a
> lib. So you pay for it only if you use it, and you don't add feature in
> the language just because it is convenient.

I'm not saying how it should be implemented, just that it should be accessible at runtime.

-- 
/Jacob Carlborg
April 10, 2012
Le 10/04/2012 00:19, Walter Bright a écrit :
> On 4/6/2012 4:20 AM, Manu wrote:
>> On 4/6/2012 2:54 AM, Timon Gehr wrote:
>> Should add additional information to the type Foo.
>> Attributes are on the declaration, and not passed around.
>
> Right, they are not added to the *type*.

No, they are not, or it will become a crazy mess.
April 10, 2012
On 04/10/2012 12:18 AM, Walter Bright wrote:
> On 4/6/2012 3:49 AM, Timon Gehr wrote:
>> On 04/06/2012 12:23 PM, Walter Bright wrote:
>>> On 4/6/2012 2:54 AM, Timon Gehr wrote:
>>>> Should add additional information to the type Foo. I don't see any
>>>> issues with
>>>> it, and not supporting it would be very strange.
>>>
>>> How would:
>>>
>>> @attr(foo) int x;
>>> int y;
>>>
>>> work? Are x and y the same type or not?
>>
>> Yes, they are.
>>
>> (But a future extension might leave this choice up to 'foo')
>>
>>> Now, consider:
>>>
>>> auto c = b ? x : y;
>>>
>>> What type does c have? int or @attr(foo)int ? And that's really just the
>>> beginning. How about:
>>>
>>> struct S(T) {
>>> T t;
>>> }
>>>
>>> Instantiate it with S!int and S!(@attr(foo)int). Are those the same
>>> instantiation, or different? If the same, does S.t have the attribute or
>>> not?
>>
>> There is no such thing as an @attr(foo) int, because @attr is not a type
>> constructor.
>
> But you said it was added to the *type*.

What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type:

@attr(foo) struct Foo{} // annotate 'foo'

@attr(bar) Foo x;

__traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar'

__traits(getAttributes, x); // this will find 'bar', but not 'foo'
April 10, 2012
On Tue, 10 Apr 2012 06:32:00 -0400, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 04/10/2012 12:18 AM, Walter Bright wrote:

>> But you said it was added to the *type*.
>
> What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type:
>
> @attr(foo) struct Foo{} // annotate 'foo'
>
> @attr(bar) Foo x;
>
> __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar'
>
> __traits(getAttributes, x); // this will find 'bar', but not 'foo'

I should clarify that it's *associated* with the type.  It should not affect the type in how it functions, at all.  For all usages of Foo except to get attributes associated with its declaration, it should be treated as if it doesn't have an attribute on it.

So it doesn't affect how the type operates or how it's matched, etc. except in the capacity that you query its attributes.

-Steve