April 06, 2012
Am Fri, 06 Apr 2012 03:06:51 -0700
schrieb Walter Bright <newshound2@digitalmars.com>:

> On 4/6/2012 2:41 AM, Johannes Pfau wrote:
> > The last time custom attributes where discussed, a C# like model was proposed. Is there a good reason why we should deviate from the C# implementation?
> 
> C# uses a runtime implementation, not a compile time one.

OK, but my post was only about the syntax, there's no runtime/compile time specific part in it (the struct's constructor has to be called using CTFE instead of at runtime, but that's the only difference I see)
April 06, 2012
On 6 April 2012 13:06, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 04/06/2012 11:57 AM, Manu wrote:
>
>> I don't think it should affect the type, although this shows a
>> conceptual problem when referring to existing attributes via the same
>> terminology. Obviously one might consider 'const', 'pure', etc
>> attributes themselves, and they clearly do affect the type.
>> Perhaps that's the key distinction between an '@'
>> attribute(/'annotation'?), and a no-'@' attribute?
>>
>
> @safe affects the type.
>

I realise that, I'm just suggesting this is a possible solution to the
confusion... if the distinction were to be made clearly.
I guess it's impossible though, can't go claiming 'safe' from the global
namespace :)


April 06, 2012
On 04/06/2012 11:41 AM, Johannes Pfau wrote:
>
> Syntax in D would be different of course, but I see absolutely no need
> for the redundant (and ugly) @attr.
>
> Declaring a custom attribute:
> ---------
> module std.something;
>
> struct Author
> {
>      string name;
>      public this(string name)
>      {
>          this.name = name;
>      }
> }
> ---------
>
> Using it:
> ---------
> import std.something; //Usual namespace lookup rules apply to attributes
>
> /*
>   * @Author(param) calls the constructor of the Author struct and
>   * attaches the struct instance to test. Probably @Author (without
>   * parenthesis) coud be made to mean std.something.Author.init
>   */
> @Author("Johannes Pfau") int test;
> ---------
>
> Attaching attributes multiple times as in C# should be possible.
>
> Using reflection to get that attribute:
> ---------
> if(__traits(hasAttribute, test, std.something.Author))
> {
>      Author[] authors = __traits(getAttribute, test,
>          std.something.Author);
> }
> ---------
>
> An array is used here to support attaching the same attribute multiple
> times. Of course "auto authors = ..." should be usable here too.
>

This all seems very reasonable. I think this is how things should work. (maybe syntax will need to be different, because Walter does not seem to like the idea of un-reserving @identifier.)
April 06, 2012
On 4/6/12 6:29 PM, Timon Gehr wrote:
> On 04/06/2012 12: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.
>>
>
> It would behave like a struct anyway. The issue is whether any struct
> should be allowed to be used as an attribute, or whether a runtime
> instance of an attribute can be created.
>
> Syntax could just as well be this:
>
> @attribute struct Foo {
> // ...
> }

True, I struct can be fine. And I don't see any problem in using it in runtime. Though I'm sure nobody would like it to remain in the obj file if it's only used at compile time...
April 06, 2012
On 04/06/2012 12:28 PM, Walter Bright wrote:
> On 4/6/2012 3:23 AM, Manu wrote:
>> What about:
>>
>> struct editor
>> {
>> this(string name, EditType, Colour = Colour.Default, string
>> description = null)
>> {
>> //...
>> }
>>
>> blah blah blah
>> }
>>
>> @attr(editor("thing",...blah...))
>
> Are you really changing the arguments for every declaration? Or is it
> one set that is repeated everywhere?
>

Yes, allowing the arguments to be different is a crucial feature.

Custom attributes are not a boolean thing, that is just the case for built-in ones. They are arbitrary data that is attached to a declaration and can then be used to build powerful semantics using compile time reflection.

>
>> I don't see the advantage over:
>> @editor(...)
>>
>> ?
>
> Name collisions with other @ attributes.
>

Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more.

Maybe we could just keep all the lower case @attributes reserved in order to be future proof.
April 06, 2012
Am Fri, 06 Apr 2012 12:43:27 +0200
schrieb Timon Gehr <timon.gehr@gmx.ch>:

> On 04/06/2012 12:28 PM, Walter Bright wrote:
> > On 4/6/2012 3:23 AM, Manu wrote:
> >> I don't see the advantage over:
> >> @editor(...)
> >>
> >> ?
> >
> > Name collisions with other @ attributes.
> >
> 
> Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more.
> 
> Maybe we could just keep all the lower case @attributes reserved in order to be future proof.

Or add a reserved pseudo-namespace (like e.g 'builtin') for compiler defined attributes and use normal namespace resolution for those:

@safe <=> @builtin.safe
April 06, 2012
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.

>
> And, whatever you choose for the semantics, what is the sensible,
> intuitive rule for it?

Custom attributes apply to the symbol declaration. Because any symbol is declared just once, there is never any ambiguity. There is no conceptual gap between

@attr(foo) int x;

and

@attr(bar) struct S{...}

Obviously @attr(bar) changes S, but there is only one declaration of S.
April 06, 2012
On 6 April 2012 13:12, Walter Bright <newshound2@digitalmars.com> 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.


I don't think it's necessary to declare the struct as @attribute explicitly, the '@' can easily imply the usage all on its own in the declaration. The struct would remain a perfectly normal struct, and will be useful if you want to get a struct somewhere in the code to inspect details about the attribute.

@SomeStruct(blah) int x;

..


SomeStruct s = __traits(getAttribute,  SomeStruct, x);
... do some stuff with the information that x was attributed
static if(s.thing == ??)




> 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.


It doesn't need to be runtime. The syntax works perfectly at compile time?


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.


Please don't. We've gone from a minor case of bracket spam now to a whole
bunch of extra lines for every single member, and you've also removed the
tight syntactical connection of the values from their attribute declaration
(one of the most important details, its safety, when people update/edit
classes). This is fast approaching the disconnected enum table which is the
whole thing we're trying to avoid.
There's also a namespace/scope problem here. 2 different systems from 2
different libraries will almost certainly use the 'serialise' attribute.


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.


See my point above, I don't think there's any need for a new symbol type... The compiler would just keep a little table of attributes alongside declarations, which you can query if you want to.


April 06, 2012
On 4/6/2012 3:27 AM, Ary Manzana wrote:
>> @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.

All the semantics of @safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined.

IUnknown's semantics are nearly all user-defined.

April 06, 2012
Walter Bright wrote:
> Are you really changing the arguments for every declaration? Or is it
> one set that is repeated everywhere?

The former.

>> I don't see the advantage over:
>> @editor(...)
>>
>> ?
>
> Name collisions with other @ attributes.

The same applies to other identifiers, like class named "class". NET has predefined attributes too, but they use the same syntax as the custom ones:

[MyAttr(5)] int x;

I think @MyAttr(5) declaration looks more readable than @attr(MyAttr(5)). To avoid name clashes, in case of using builtin name, qualified identifier should be used:

@myModule.pure
@pure
void fn() {}