April 07, 2012
Jacob Carlborg wrote:
> On 2012-04-07 00:40, Piotr Szturmaj wrote:
>
>> Ok, but it needs more work in the compiler, comparing to identifier
>> search and remembering expression tuple of a symbol. Also, I just found
>> a major drawback of this approach: consider parameterless attributes
>> like @NotNull. What would you return from function named NotNull()?
>
> void ?

I know that's the answer, but how would you store void, and get it from __traits(getAttributes) ?
April 07, 2012
Le 07/04/2012 13:32, Kapps a écrit :
> On Saturday, 7 April 2012 at 11:13:54 UTC, deadalnix wrote:
>> Le 07/04/2012 05:29, Kapps a écrit :
>>> I slightly prefer this function method over the struct method because:
>>> 1) No need to generate a custom struct for everything. Plenty of things
>>> are just a true or false, or a string. Saves a little bit of TypeInfo
>>> generation.
>>
>> If the type isn't used at runtime, the compiler should be able to
>> remove that dead part of the code. If it doesn't, it is an
>> implementation issue, and shouldn't be solved by language design
>> decision.
>
> This is not possible currently. The TypeInfo is required at runtime
> whether or not the type is used at compile-time, for reasons such as
> Object.factory.

Object.factory is limited to classes IIRC.
April 07, 2012
On 2012-04-07 05:29, Kapps wrote:

> I slightly prefer this function method over the struct method because:
> 1) No need to generate a custom struct for everything. Plenty of things
> are just a true or false, or a string. Saves a little bit of TypeInfo
> generation.

But you still need to create a function.

> 2) The more important one: The possibility to eventually include an
> alias template parameter. This allows things like looking up whether the
> symbol with the attribute has other attributes applied, or determining
> type. This allows things like constraints, and can be a nice benefit.

This can't be done for structs?

-- 
/Jacob Carlborg
April 07, 2012
On 2012-04-07 13:32, Kapps wrote:

> This is not possible currently. The TypeInfo is required at runtime
> whether or not the type is used at compile-time, for reasons such as
> Object.factory.

Object.factory can only create instances of classes.

-- 
/Jacob Carlborg
April 07, 2012
On 2012-04-07 16:30, Piotr Szturmaj wrote:
> Jacob Carlborg wrote:
>> On 2012-04-07 00:40, Piotr Szturmaj wrote:
>>
>>> Ok, but it needs more work in the compiler, comparing to identifier
>>> search and remembering expression tuple of a symbol. Also, I just found
>>> a major drawback of this approach: consider parameterless attributes
>>> like @NotNull. What would you return from function named NotNull()?
>>
>> void ?
>
> I know that's the answer, but how would you store void, and get it from
> __traits(getAttributes) ?

The compiler would only store that the attribute is attached to the declaration. In this case only "hasAttribute" is of interest.

-- 
/Jacob Carlborg
April 08, 2012
After reading the thread my vote goes to the struct proposal.
The two approaches functions vs. structs are functionally equivalent but conceptually structs are preferable. Attributes are meta _data_ which is conceptually associated with types whereas functions are conceptually associated with behaviour.  simply put - structs are the more intuitive choice.
There are valid concerns raised about the implementation - code bloat, struct default ctor, etc. those are implementation concerns that should be handled in the compiler and not in the language design.

April 08, 2012
Am Fri, 06 Apr 2012 16:53:56 +0200
schrieb Timon Gehr <timon.gehr@gmx.ch>:

> On 04/06/2012 04:23 PM, Steven Schveighoffer wrote:
> > Why should we be restricted to only structs? Or any type for that matter?
> >
> 
> A restriction to only structs is not a restriction because structs can have arbitrary field types.

+1

> > The benefit to using CTFE functions is that the compiler already knows how to deal with them at compile-time. i.e. less work to make the compiler implement this.
> >
> 
> It is exactly the same amount of work because CTFE is able to execute struct constructors.

Yep. Well, in the end the older idea of attributes == structs/classes is - as Adam D. Ruppe said - exchanging the constructor for a function call. You can do the same as with structs/classes and a little more (return basic types). IDEs can work with this proposal. And if we have to prepend @attribute to our CTFE-attribute-functions or attribute-structs that's fine, too with me. :)

While I give Steven a virtual karma point for making it clear that not "everything is an object" (or struct) with his idea, I prefer structs-only over functions, because we could augment these structs with compiler recognized methods/fields at a later point. Think of the range interface here, which is implicit. Some examples:

@attribute struct MyAttribute {
	// this attribute-struct is allowed multiple times on a symbol
	enum bool allowMultiple = true;

	// cannot be used on classes, but structs, methods and fields
	enum uint appliesTo = Fields | Methods | Structs;

	// Run any action in context of the filled attribute structure and
	// the type it is applied to. With CTFE I/O, it could generate
	// binaries or text files with bindings.
	void onInvokation(T)() { … }

	void invariant() { static assert(author, "Author must be given.") }

	string author;
	string email = "no email;
}

@MyAttribute(author = "Some Name", email = "some@email")
@MyAttribute(author = "Someone Else", email = "else@email")
struct Test { … }

All of this is nice-to-have at most. I imagine it becomes interesting when attributes are offered by libraries, and you want to give the user of your attributes some validation and convenience. E.g. the compiler can guarantee that only allowMultiple-attributes appear multiple times, so you can focus on implementing the logic instead of checking for usage errors.

-- 
Marco

April 09, 2012
On Sat, 07 Apr 2012 09:59:27 -0400, Jacob Carlborg <doob@me.com> wrote:

> On 2012-04-06 19:36, Steven Schveighoffer wrote:
>> so now I must define a type for every attribute? I'd rather just define
>> a function.
>>
>> What if I have 20 string attributes, I must define a new attribute type
>> for each one? This seems like unneeded bloat.
>
> If we want to be able to pass a key-value list to the attribute, I think a struct is needed.

What if they have nothing to do with each other?  What I'm getting at is, I don't want to define a struct just so I can pass a string.  It's unnecessary.

> BTW, could both structs and functions be allowed?

Yes, I replied early on to Timon Gehr, this should be allowed.  Simply because a struct ctor is a function like any other function, called by a standard D symbol.  It doesn't make sense if you don't allow it, because it's so easy to create a factory method that forwards to it.

-Steve
April 09, 2012
On Fri, 06 Apr 2012 18:40:29 -0400, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:

> Steven Schveighoffer wrote:
>>
>>
>> Unused function do not make it into the EXE.
>
> Are unused structs compiled into EXE?

Their TypeInfo_Struct is.  If they are compiled in their own module, then I think it's possible the linker will leave the whole object out.

>> foreach(name, value; __traits(getAttributes, symbol)) {...}
>>
>> hereby added to the proposal.
>
> Ok, but how do you filter that and pass the result to another template? It should be easy if __traits(getAttributes, symbol) would return an expression tuple, which is what I'd like to see.

It has to be a tuple, since the type of value may change on each iteration.  It likely must be a tuple of name-value tuples.

>> No, it doesn't generate more typeinfo that must go into the EXE. When
>> the EXE is built, all associated bloat should disappear, it's only
>> needed during compilation.
>
> Those types are only needed during compilation too. However, I don't know if they're always included into binary or only when they're used.

I think they are.  I don't know if it's required though.  I don't know enough about the link-time optimizations available to see if they can be weeded out if unused.

>>
>> I think you are missing how the metadata is stored as key-value pairs,
>> with the key being the name of the function that was used.
>
> Ok, but it needs more work in the compiler, comparing to identifier search and remembering expression tuple of a symbol.

The compiler can "build" a struct if it wants to, it reduces to the equivalent problem.

> Also, I just found a major drawback of this approach: consider parameterless attributes like @NotNull. What would you return from function named NotNull()?

void?  There is no need to store a type, it's just "is NotNull valid or not?".  Note that this is somewhat of a red herring, a NotNull attribute cannot implement what it purports to.

>>> This is how it's done in C# by the way.
>>
>> Yes I know. I don't think we need to limit ourselves this way, C# does
>> not have the compile-time power that D does.
>
> I didn't state that we shouldn't use compile-time :)

My point was, maybe C# took this route specifically because their lack of compile-time facilities didn't allow them a better solution like mine ;)

-Steve
April 09, 2012
On Sat, 07 Apr 2012 10:00:19 -0400, Jacob Carlborg <doob@me.com> wrote:

> On 2012-04-06 19:37, Steven Schveighoffer wrote:
>> On Fri, 06 Apr 2012 12:53:51 -0400, Piotr Szturmaj
>>> struct Author { string name = "empty"; }
>>> // struct Author { string name; } - this works too
>>
>> I think the point is, we should disallow:
>>
>> @Author int x;
>>
>> -Steve
>
> Why?

I misspoke.  The person who implemented the @Author attribute probably wants to disallow specifying an Author attribute without a name.  I don't think we should disallow that on principle, I meant in the context it should be disallowed.

-Steve