Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Jacob Carlborg

On 2012-04-09 15:29, Steven Schveighoffer wrote:


I think the struct approach is fine for some attributes, and I think it
should be doable to @attribute either functions or structs. I just want
the most generic, basic feature possible. I think Timon has the best
idea that any callable CTFE symbol should be able to be an attribute.


Using any callable CTFE symbol would make sense.

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Jacob Carlborg

On 2012-04-09 15:20, Steven Schveighoffer wrote:


The argument was to use the name of the type returned as the attribute
name instead of the function. That is not my proposal. The suggested
case is to be able to use a different name to build the same attribute,
to be more intuitive.

i.e. both area and square create the Area attribute, but square only
takes one parameter because it's a square. Kind of like saying "the area
is square".

So my counter point above is in the context that the type name of the
return value becomes the attribute name.

-Steve



Aha, I see.

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Marco Leise
Am Mon, 09 Apr 2012 09:13:51 -0400
schrieb "Steven Schveighoffer" :

> On Sat, 07 Apr 2012 10:00:19 -0400, Jacob Carlborg  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

Yes, when libraries start to offer attributes, their authors likely want to add 
some static checking. Either as an invariant() with the struct solution, or 
static asserts in the function.

Java and C# also offer attributes for attributes to:
- allow multiple attributes of the same kind on a symbol
- restrict the attribute to certain symbol types (function, struct, ...)
- inherit attributes down a class hierarchy
I thought I'd just mention it all here in one go as "attribute constraints".

-- 
Marco



Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer

On Sat, 07 Apr 2012 12:48:00 -0400, Jacob Carlborg  wrote:


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.


functions are easier for the linker to deal with.  The main point here is,  
no TypeInfo needed.





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?


IFTI.  It possibly can be added to struct ctors (I argue it should be),  
but is not today.


I think the struct approach is fine for some attributes, and I think it  
should be doable to @attribute either functions or structs.  I just want  
the most generic, basic feature possible.  I think Timon has the best idea  
that any callable CTFE symbol should be able to be an attribute.


At this point it has become a "structs are a good solution, why not also  
allow functions?" argument.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer

On Sat, 07 Apr 2012 10:11:16 -0400, Jacob Carlborg  wrote:


On 2012-04-06 20:52, Steven Schveighoffer wrote:


Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?


Isn't "square" the name of the attribute? In that case you would use:

__traits(getAttribute, foo, square)


The argument was to use the name of the type returned as the attribute  
name instead of the function.  That is not my proposal.  The suggested  
case is to be able to use a different name to build the same attribute, to  
be more intuitive.


i.e. both area and square create the Area attribute, but square only takes  
one parameter because it's a square.  Kind of like saying "the area is  
square".


So my counter point above is in the context that the type name of the  
return value becomes the attribute name.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer

On Sat, 07 Apr 2012 07:26:26 -0400, deadalnix  wrote:


Le 06/04/2012 22:46, Mafi a écrit :

Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?

Another possibility:

@attribute Area area(int w, int h) { return Area(w, h);}
@attribute Area area(Area a) { return a;}

Area square(int a) { return Area(a, a);}

@area(5, 5) int foo();
@area(square(5)) int bar();

-Steve


The second possibility looks good. Especially because the lack of
@attribute on square disallows @square.

Mafi


This is adding code just for the pleasure of adding more code. Why wan't  
I construct Area directly as attribute ?


See http://forum.dlang.org/post/op.wcct2shqeav7ka@localhost.localdomain

I think you should be able to construct it by @attribute'ing a struct.   
But this sub-thread is about changing the name of the function for  
construction purposes, but keeping the type as the attribute name.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer

On Sat, 07 Apr 2012 10:00:19 -0400, Jacob Carlborg  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


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 18:40:29 -0400, Piotr Szturmaj   
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


Re: custom attribute proposal (yeah, another one)

2012-04-09 Thread Steven Schveighoffer

On Sat, 07 Apr 2012 09:59:27 -0400, Jacob Carlborg  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


Re: custom attribute proposal (yeah, another one)

2012-04-08 Thread Marco Leise
Am Fri, 06 Apr 2012 16:53:56 +0200
schrieb Timon Gehr :

> 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



Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread foobar

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.




Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread deadalnix

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.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Piotr Szturmaj

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) ?


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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 ?

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

On 2012-04-06 20:52, Steven Schveighoffer wrote:


Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?


Isn't "square" the name of the attribute? In that case you would use:

__traits(getAttribute, foo, square)

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

On 2012-04-06 19:51, bls wrote:


Why not being more flexible .. Likewise

struct Annotation //Throw in all your annotations
{

Variant[] [string] map;

Variant[] opDispatch(string key)()
{
return map[key];
}

// Single value
Variant[] opDispatch(string key, T) (T t )
if ( !isArray!T && !isTuple!T )
{
index ~= key;
map[key] ~= to!Variant(t);
return map[key];
}
Array, Tuple
}
well.. I am not sure about CTFE


Variant yet again. What with this Variant all the time.

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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.


@attribute struct Author
{
string name;
string email;
}

@Author(name = "John Doe", email = "j...@doe.com") struct Foo {}

BTW, could both structs and functions be allowed?

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Jacob Carlborg

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?

--
/Jacob Carlborg


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Manu
On 7 April 2012 14:35, Kapps  wrote:

> On Saturday, 7 April 2012 at 11:25:15 UTC, Manu wrote:
>
>>
>> Generating a struct for an attribute is fine. It's not like you go on
>> a custom attribute frenzy attributing everything with different stuff. You
>> may have a few useful attributes, and those given by libs that you just
>> use.
>> Why can't you use alias template parameters in a struct definition in just
>> the same way?
>>
>> Structs are definitely preferable in my opinion, for the fact that they
>> can
>> have methods and properties and stuff. If you get an attribute of
>> something, being about to use methods on it, or access calculated data via
>> properties will be useful.
>> I see no reason to name an attribute differently than the thing that
>> happens to define it.
>>
>
> The calling methods is a valid point, however the method can return a
> struct as well.
>
> Ultimately, I don't think it makes a large difference at all which is
> used. I'm just leaning towards methods because there's less bloat, no
> issues with this() like with a struct, and can be slightly simpler in
> certain situations.
>
> Again, it's mostly minor things. I'd be quite happy with either approach.
>

Yeah I'm happy either way. At the end of the day, I guess whoever actually
implements the feature will just follow their preference ;)


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Kapps

On Saturday, 7 April 2012 at 11:25:15 UTC, Manu wrote:


Generating a struct for an attribute is fine. It's not like you 
go on
a custom attribute frenzy attributing everything with different 
stuff. You
may have a few useful attributes, and those given by libs that 
you just use.
Why can't you use alias template parameters in a struct 
definition in just

the same way?

Structs are definitely preferable in my opinion, for the fact 
that they can
have methods and properties and stuff. If you get an attribute 
of
something, being about to use methods on it, or access 
calculated data via

properties will be useful.
I see no reason to name an attribute differently than the thing 
that

happens to define it.


The calling methods is a valid point, however the method can 
return a struct as well.


Ultimately, I don't think it makes a large difference at all 
which is used. I'm just leaning towards methods because there's 
less bloat, no issues with this() like with a struct, and can be 
slightly simpler in certain situations.


Again, it's mostly minor things. I'd be quite happy with either 
approach.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Kapps

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.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Manu
On 7 April 2012 06:29, Kapps  wrote:

> On Friday, 6 April 2012 at 13:23:03 UTC, Steven Schveighoffer wrote:
>
>> OK, so I woke up this morning to find a huge discussion on attributes,
>> and I'd like to once again propose the idea of how to define and use an
>> attribute.
>>
>> I do not like the idea of:
>>
>> @attr(identifier)
>>
>> Why?  Because what the hell did we create that "@" syntax for?  I though
>> it was to avoid misinterpreting such things as normal symbols, and avoid
>> creating new keywords.  Why should the compiler be the only one able to use
>> such symbols?
>>
>> Another thing I don't like is some idea that only a certain type of
>> construct can be the identifier.  An attribute should have one requirement
>> -- that it can be created/determined at compile time.
>>
>
> Either this or the one that's the same just with structs is the way to go.
> The original proposal by Walter is good, it's just a little verbose.
>
> 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.
> 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.
>
> On the topic of type vs storage, it is useful to be able to apply
> attributes to a type, but this should /not/ change the type itself. It must
> be transparent to the user what attributes a type has unless they're
> actually accessing attributes.
>

Generating a struct for an attribute is fine. It's not like you go on
a custom attribute frenzy attributing everything with different stuff. You
may have a few useful attributes, and those given by libs that you just use.
Why can't you use alias template parameters in a struct definition in just
the same way?

Structs are definitely preferable in my opinion, for the fact that they can
have methods and properties and stuff. If you get an attribute of
something, being about to use methods on it, or access calculated data via
properties will be useful.
I see no reason to name an attribute differently than the thing that
happens to define it.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread deadalnix

Le 06/04/2012 22:46, Mafi a écrit :

Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?

Another possibility:

@attribute Area area(int w, int h) { return Area(w, h);}
@attribute Area area(Area a) { return a;}

Area square(int a) { return Area(a, a);}

@area(5, 5) int foo();
@area(square(5)) int bar();

-Steve


The second possibility looks good. Especially because the lack of
@attribute on square disallows @square.

Mafi


This is adding code just for the pleasure of adding more code. Why wan't 
I construct Area directly as attribute ?


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread deadalnix

Le 07/04/2012 09:10, Johannes Pfau a écrit :

But as long as you mark attribute structs in some special way
(@attribute struct Author), this can also be guaranteed for structs.
Afaik ignoring unused functions is currently done by the linker, but I
think functions/structs only used for attributes should probably never
make it to the linker. I think we already had cases were linkers didn't
strip unused functions for some reason?

Regarding code bloat: If struct initializers could be used with
attributes, a constructor isn't necessary and the minimal code is:
--
@attribute struct Author
{
 string name;
}

@Author("Johannes Pfau") int test;
or
@Author{name: "Johannes Pfau"} int test;
--

That's exactly as much code as using functions:
--
@attribute string Author(string name)
{
 return name;
}

@Author("Johannes Pfau") int test;
--


I don't have a strong opinion whether storable types should be limited
to structs, but I think classes add little benefit and complicate
things because of inheritance (at least if you query attributes by
type). What we want to do here is store _data_ and the D style is to
use structs for pure data. Basic types could be useful too but when
querying by type, those can't work well.



For basic type :

alias int foobar;
@foobar(2) someDeclaration;

No benefit in introducing a new syntax.


BTW: I think there's one thing both your and my proposals are missing:

The function/constructor returning the data must be pure: We can't
guarantee this function will be executed only once, but the value of
the attribute should always be the same. Consider this scenario:

a.d

@RandomNumber() int test;


b.d
---
auto value1 = __traits(getAttribute, a.test, RandomNumber);
---

c.d
---
auto value2 = __traits(getAttribute, a.test, RandomNumber);
---

All files are compiled individually. Now the compiler has to call
RandomNumber() 2 times: one time for b.d and one time for c.d, but
value1 should be the same as value2.



RandomNumber is something that shouldn't be CTFEable, if it does what 
the name says.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread deadalnix

Le 07/04/2012 05:29, Kapps a écrit :

On the topic of type vs storage, it is useful to be able to apply
attributes to a type, but this should /not/ change the type itself. It
must be transparent to the user what attributes a type has unless
they're actually accessing attributes.



Then put the attribute at type declaration, not where it is used.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread deadalnix

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.


Re: custom attribute proposal (yeah, another one)

2012-04-07 Thread Johannes Pfau
Am Fri, 06 Apr 2012 16:33:21 -0400
schrieb "Steven Schveighoffer" :

> On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj
>  wrote:
> 
> > Steven Schveighoffer wrote:
> 
> >> What if I have 20 string attributes, I must define a new attribute
> >> type for each one? This seems like unneeded bloat.
> >
> > I don't see advantage of functions here, twenty of them is also a
> > bloat. Different types give you different _names_ for different
> > purposes. Those _names_ are crucial to support the attributes.
> 
> Unused function do not make it into the EXE.

But as long as you mark attribute structs in some special way
(@attribute struct Author), this can also be guaranteed for structs.
Afaik ignoring unused functions is currently done by the linker, but I
think functions/structs only used for attributes should probably never
make it to the linker. I think we already had cases were linkers didn't
strip unused functions for some reason?

Regarding code bloat: If struct initializers could be used with
attributes, a constructor isn't necessary and the minimal code is:
--
@attribute struct Author
{
string name;
}

@Author("Johannes Pfau") int test;
or
@Author{name: "Johannes Pfau"} int test;
--

That's exactly as much code as using functions:
--
@attribute string Author(string name)
{
return name;
}

@Author("Johannes Pfau") int test;
--


I don't have a strong opinion whether storable types should be limited
to structs, but I think classes add little benefit and complicate
things because of inheritance (at least if you query attributes by
type). What we want to do here is store _data_ and the D style is to
use structs for pure data. Basic types could be useful too but when
querying by type, those can't work well.


BTW: I think there's one thing both your and my proposals are missing:

The function/constructor returning the data must be pure: We can't
guarantee this function will be executed only once, but the value of
the attribute should always be the same. Consider this scenario:

a.d

@RandomNumber() int test;


b.d
---
auto value1 = __traits(getAttribute, a.test, RandomNumber);
---

c.d
---
auto value2 = __traits(getAttribute, a.test, RandomNumber);
---

All files are compiled individually. Now the compiler has to call
RandomNumber() 2 times: one time for b.d and one time for c.d, but
value1 should be the same as value2.




Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Kapps
On Friday, 6 April 2012 at 13:23:03 UTC, Steven Schveighoffer 
wrote:
OK, so I woke up this morning to find a huge discussion on 
attributes, and I'd like to once again propose the idea of how 
to define and use an attribute.


I do not like the idea of:

@attr(identifier)

Why?  Because what the hell did we create that "@" syntax for?  
I though it was to avoid misinterpreting such things as normal 
symbols, and avoid creating new keywords.  Why should the 
compiler be the only one able to use such symbols?


Another thing I don't like is some idea that only a certain 
type of construct can be the identifier.  An attribute should 
have one requirement -- that it can be created/determined at 
compile time.


Either this or the one that's the same just with structs is the 
way to go. The original proposal by Walter is good, it's just a 
little verbose.


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


On the topic of type vs storage, it is useful to be able to apply 
attributes to a type, but this should /not/ change the type 
itself. It must be transparent to the user what attributes a type 
has unless they're actually accessing attributes.




Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread deadalnix

Le 06/04/2012 15:23, Steven Schveighoffer a écrit :

OK, so I woke up this morning to find a huge discussion on attributes,
and I'd like to once again propose the idea of how to define and use an
attribute.

I do not like the idea of:

@attr(identifier)

Why? Because what the hell did we create that "@" syntax for? I though
it was to avoid misinterpreting such things as normal symbols, and avoid
creating new keywords. Why should the compiler be the only one able to
use such symbols?

Another thing I don't like is some idea that only a certain type of
construct can be the identifier. An attribute should have one
requirement -- that it can be created/determined at compile time.

So here is my proposal:

1. Introduce a new compiler-defined attribute @attribute (or @attr or
something better, the name isn't important).
2. This attribute can *only* be used on a module-level function.
3. @attribute functions *must* be CTFE-able.
4. An @attribute function can be used as a user-defined attribute on any
declaration using the syntax @identifier where identifier is the name of
the attribute function (subject to normal function lookup rules). If the
attribute can be called without parameters, the parentheses are optional.
5. When used on a declaration, that CTFE function is called during
compile-time, and the result of that function is stored as metadata on
that symbol. It does not affect the type of the symbol or transfer to
any other symbols that are assigned to the value of that declaration (in
other words, it *cannot* be used as a type constructor).
6. The metadata is stored in a key-value pair, with the key being the
symbol of the @attribute function, and the value being the result of the
CTFE function.
7. One can lookup whether an attribute exists on a symbol using
__traits(hasAttribute, symbol).
8. One can retrieve the value of the CTFE result using
__traits(getAttribute, symbol). If the CTFE function returns void, this
is a compiler error.

And that's it. We can extend this eventually to storing something in
TypeInfo, but I'm not sure we need that. However, I want to stress that
having runtime type metadata is not a requirement for this proposal.

Example usage:

@attribute bool serializable(bool yesorno = true) { return yesorno; }

unittest {
// serializable is a normal function also
assert(serializable() == true);
assert(serializable(true) == true);
assert(serializable(false) == false);
}

@serializable struct MyType
{
int x;
int y;
@serializable(false) int z;
}

string serialize(T)(const ref T t) if (__traits(hasAttribute,
serializable) && __traits(getAttribute, serializable))
{
// serialize each field. Skip any fields that are marked as serializable
== false
}

-Steve


The struct proposal from previous thread was superior because it provide 
similar capability without as much language change.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj
 wrote:


Steven Schveighoffer wrote:



What if I have 20 string attributes, I must define a new attribute type
for each one? This seems like unneeded bloat.


I don't see advantage of functions here, twenty of them is also a
bloat. Different types give you different _names_ for different
purposes. Those _names_ are crucial to support the attributes.


Unused function do not make it into the EXE.


Are unused structs compiled into EXE?


How do you get list of all attributes with your function based
proposal? You can get a string attribute but you don't know which
function generated it. You don't know if it was serializable, author
or whatever.


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.



BTW, if I wasn't trying to demonstrate that you could store structs, I
would have written:

@attrubte string author(string name) { return name;}

and save the extra bloat associated with declaring another type. Maybe
we could even get this someday:


As above, declaring another function is also a bloat.


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.



@attribute author(string name) => name;

I just don't see the need to declare a type that can wrap a string.

You could even add this rule:

if @attribute is placed on a struct, its constructor becomes an
@attribute qualified function with the name of the struct as the
attribute name.


Consider struct constructors as equivalent of functions proposed by
you. Here you declare a type, there you declare a function. They're
very similar, besides that struct type _describes_ the attribute. A
function on the other side just returns a value, which doesn't have
any name attached to it.


The name is the function. You seem to be arguing the equivalent of:

"int x is useless. It should really just be int. If you need another
integer field, make a new type that's just like int, how hard is that?"

Yeah, I know it's a strawman, but this is seriously how it sounds to me ;)


If you have simple attributes in mind, like name = string value, then 
yes, but most attributes are not that simple. Most of the time you will 
be forced to create a struct anyway (and return it from function).



It's an example. you can choose any type you want! I actually just want
the name of the author, I don't care whether that's a struct, or a
string.


Yes, but my point is that you get a bool and you don't know which of
the functions returned it, as many of them can return bool.


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



Any CTFE computed value should suffice.


I think that list of attributes should be a list of user defined
types. You can always write a function to construct them, but anyway
you get named user defined type (like struct). Named type easily
disambiguates between different attributes without resorting to
name-value solutions.


Again, see point above about not naming variables.


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 :)


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 15:06:47 -0400, Piotr Szturmaj

See also: http://forum.dlang.org/post/jlmtcv$v09$1...@digitalmars.com


Excellent point, passing the symbol being annotated (probably should be
an alias) should definitely be added. Then you could easily limit what
attributes can be attached to!


Yes, I forgot to add "alias". I think this is the best approach to 
support attribute constraints. We can write some library mixins to 
support common cases like limiting the number of attributes or allowing 
simple targets (if we choose UDTs for attributes):


struct Attr
{
// allows multiple attachments, but for classes and structs only
mixin AttrConstraint!(true, AttrTarget.Class | AttrTarget.Struct);
}


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Mafi

Am 06.04.2012 20:52, schrieb Steven Schveighoffer:

On Fri, 06 Apr 2012 14:23:45 -0400, Mafi  wrote:



There's one difference I think.
struct approach:
struct Area { int x, y; }
Area sqare(int a) { return Area(x, y); }
//foo and bar are attributed the same
@Area(5, 5) int foo();
@square(5) int bar();

whereas with the function approach:
@area(5, 5) int foo();
@square(5) int bar();
foo and bar have different attributes.


[...]

Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?

Another possibility:

@attribute Area area(int w, int h) { return Area(w, h);}
@attribute Area area(Area a) { return a;}

Area square(int a) { return Area(a, a);}

@area(5, 5) int foo();
@area(square(5)) int bar();

-Steve


The second possibility looks good. Especially because the lack of 
@attribute on square disallows @square.


Mafi


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 15:06:47 -0400, Piotr Szturmaj   
wrote:



Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 13:33:33 -0400, Tove  wrote:

I think this proposal pretty much covers what I would expect from
'custom attributes'... but what about adding a D twist, getting "what
we annotate" as a template parameter so that one among other things
can make use of Template Constraints?


Interesting, so something like:

@attribute string defaultName(T)() if(is(typeof(T.init.name))) { return
T.init.name;}

Not sure how much this gives us, but it definitely feels doable.


See also: http://forum.dlang.org/post/jlmtcv$v09$1...@digitalmars.com


Excellent point, passing the symbol being annotated (probably should be an  
alias) should definitely be added.  Then you could easily limit what  
attributes can be attached to!


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj   
wrote:



Steven Schveighoffer wrote:



What if I have 20 string attributes, I must define a new attribute type
for each one? This seems like unneeded bloat.


I don't see advantage of functions here, twenty of them is also a bloat.  
Different types give you different _names_ for different purposes. Those  
_names_ are crucial to support the attributes.


Unused function do not make it into the EXE.

How do you get list of all attributes with your function based proposal?  
You can get a string attribute but you don't know which function  
generated it. You don't know if it was serializable, author or whatever.


foreach(name, value; __traits(getAttributes, symbol)) {...}

hereby added to the proposal.




BTW, if I wasn't trying to demonstrate that you could store structs, I
would have written:

@attrubte string author(string name) { return name;}

and save the extra bloat associated with declaring another type. Maybe
we could even get this someday:


As above, declaring another function is also a bloat.


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.



@attribute author(string name) => name;

I just don't see the need to declare a type that can wrap a string.

You could even add this rule:

if @attribute is placed on a struct, its constructor becomes an
@attribute qualified function with the name of the struct as the
attribute name.


Consider struct constructors as equivalent of functions proposed by you.  
Here you declare a type, there you declare a function. They're very  
similar, besides that struct type _describes_ the attribute. A function  
on the other side just returns a value, which doesn't have any name  
attached to it.


The name is the function.  You seem to be arguing the equivalent of:

"int x is useless.  It should really just be int.  If you need another  
integer field, make a new type that's just like int, how hard is that?"


Yeah, I know it's a strawman, but this is seriously how it sounds to me ;)


It's an example. you can choose any type you want! I actually just want
the name of the author, I don't care whether that's a struct, or a  
string.


Yes, but my point is that you get a bool and you don't know which of the  
functions returned it, as many of them can return bool.


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.



Any CTFE computed value should suffice.


I think that list of attributes should be a list of user defined types.  
You can always write a function to construct them, but anyway you get  
named user defined type (like struct). Named type easily disambiguates  
between different attributes without resorting to name-value solutions.


Again, see point above about not naming variables.


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.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread David Gileadi

On 4/6/12 6:23 AM, Steven Schveighoffer wrote:

6. The metadata is stored in a key-value pair, with the key being the
symbol of the @attribute function, and the value being the result of the
CTFE function.


There may be a good reason why it's not supported, but in Java I've 
often wished I could repeat an annotation with different values. 'Twould 
be fantastic if D allowed this.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 13:33:33 -0400, Tove  wrote:

I think this proposal pretty much covers what I would expect from
'custom attributes'... but what about adding a D twist, getting "what
we annotate" as a template parameter so that one among other things
can make use of Template Constraints?


Interesting, so something like:

@attribute string defaultName(T)() if(is(typeof(T.init.name))) { return
T.init.name;}

Not sure how much this gives us, but it definitely feels doable.


See also: http://forum.dlang.org/post/jlmtcv$v09$1...@digitalmars.com


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj
 wrote:


Steven Schveighoffer wrote:

You can store a struct, just return it from an attribute function.

e.g.:

@attribute Author author(string name) { return Author(name);}


Compare it to:

struct Author { string name; }

@Author("John Doe") int x;


so now I must define a type for every attribute? I'd rather just define
a function.


So declaration is always needed, no matter what attribute is.


What if I have 20 string attributes, I must define a new attribute type
for each one? This seems like unneeded bloat.


I don't see advantage of functions here, twenty of them is also a bloat. 
Different types give you different _names_ for different purposes. Those 
_names_ are crucial to support the attributes.


How do you get list of all attributes with your function based proposal? 
You can get a string attribute but you don't know which function 
generated it. You don't know if it was serializable, author or whatever.



BTW, if I wasn't trying to demonstrate that you could store structs, I
would have written:

@attrubte string author(string name) { return name;}

and save the extra bloat associated with declaring another type. Maybe
we could even get this someday:


As above, declaring another function is also a bloat.


@attribute author(string name) => name;

I just don't see the need to declare a type that can wrap a string.

You could even add this rule:

if @attribute is placed on a struct, its constructor becomes an
@attribute qualified function with the name of the struct as the
attribute name.


Consider struct constructors as equivalent of functions proposed by you. 
Here you declare a type, there you declare a function. They're very 
similar, besides that struct type _describes_ the attribute. A function 
on the other side just returns a value, which doesn't have any name 
attached to it.



Why should we be restricted to only structs? Or any type for that
matter?


When using __traits(getAttributes, ...) you ask for conrete (struct)
type and you get it. In case of function you ask for serializable but
you get a bool.


It's an example. you can choose any type you want! I actually just want
the name of the author, I don't care whether that's a struct, or a string.


Yes, but my point is that you get a bool and you don't know which of the 
functions returned it, as many of them can return bool.



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.


Compiler can easily deal with structs too:


I concede this is probably a non-issue.


I also firmly believe that determining what is allowed as attributes
should be opt-in. Just allowing any struct/class/function/etc. would
lead to bizarre declarations.


C# has requirement that attributes are classes that derive from base
Attribute class. But without that limitation you can do things like:

@Uuid("...")
interface MyIntf { }

without explicitly declaring Uuid as attribute. However, I don't see
any usage for primitive types:

@5
@"s"
@false


I don't understand what you are saying here.


"Just allowing any struct/class/function/etc. would
lead to bizarre declarations."

Allowing _any_ type would indeed lead to bizarre declarations, but I 
think that allowing any struct or class may be useful.


Alternatively structs or classes may require some additional member. 
This will allow only selected types to work as attributes.



I think that allowing values of structs, classes and _eventually_
enums should be enough.


Any CTFE computed value should suffice.


I think that list of attributes should be a list of user defined types. 
You can always write a function to construct them, but anyway you get 
named user defined type (like struct). Named type easily disambiguates 
between different attributes without resorting to name-value solutions.


This is how it's done in C# by the way.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer

On Fri, 06 Apr 2012 14:23:45 -0400, Mafi  wrote:


Am 06.04.2012 17:17, schrieb Adam D. Ruppe:

On Friday, 6 April 2012 at 15:07:04 UTC, Manu wrote:

But maybe the function approach has an
effect on the simplicity of the expression for a simple attribute,
like a single bool?


Meh, it is pretty similar:

struct Serializable { bool yes; }
bool Serializable(bool yes) { return yes; }



There's one difference I think.
struct approach:
struct Area { int x, y; }
Area sqare(int a) { return Area(x, y); }
//foo and bar are attributed the same
@Area(5, 5) int foo();
@square(5) int bar();

whereas with the function approach:
@area(5, 5) int foo();
@square(5) int bar();
foo and bar have different attributes.

The problem is you can't define forwarding functions because the symbol  
is the attribute type. This seems to be a major problem to me.


I acknowledge this limitation.  But we can also overload functions:

@attribute Area area(int w, int h) { return Area(w, h);}
@attribute Area area(int w) { return Area(w, w);}

Granted, area is not as obvious as square (it's actually a bad name, it  
should be something like dimensions), but being able to have more than one  
attribute of the same type I think is essential.


Also, if I see:

@square(5) int foo();

How do I know that I have to use __traits(getAttribute, foo, Area)?

Another possibility:

@attribute Area area(int w, int h) { return Area(w, h);}
@attribute Area area(Area a) { return a;}

Area square(int a) { return Area(a, a);}

@area(5, 5) int foo();
@area(square(5)) int bar();

-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Mafi

Am 06.04.2012 17:17, schrieb Adam D. Ruppe:

On Friday, 6 April 2012 at 15:07:04 UTC, Manu wrote:

But maybe the function approach has an
effect on the simplicity of the expression for a simple attribute,
like a single bool?


Meh, it is pretty similar:

struct Serializable { bool yes; }
bool Serializable(bool yes) { return yes; }



There's one difference I think.
struct approach:
struct Area { int x, y; }
Area sqare(int a) { return Area(x, y); }
//foo and bar are attributed the same
@Area(5, 5) int foo();
@square(5) int bar();

whereas with the function approach:
@area(5, 5) int foo();
@square(5) int bar();
foo and bar have different attributes.

The problem is you can't define forwarding functions because the symbol 
is the attribute type. This seems to be a major problem to me.


Mafi


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Tove
On Friday, 6 April 2012 at 17:44:25 UTC, Steven Schveighoffer 
wrote:
On Fri, 06 Apr 2012 13:33:33 -0400, Tove  
wrote:
I think this proposal pretty much covers what I would expect 
from 'custom attributes'... but what about adding a D twist, 
getting "what we annotate" as a template parameter so that one 
among other things can make use of Template Constraints?


Interesting, so something like:

@attribute string defaultName(T)() if(is(typeof(T.init.name))) 
{ return T.init.name;}


Not sure how much this gives us, but it definitely feels doable.

-Steve


yes, exactly... well, once library designers start getting 
creative, one of the immediate benefits would be, easy to 
understand error-messages.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread bls

On 04/06/2012 10:51 AM, bls wrote:

On 04/06/2012 07:04 AM, Manu wrote:

I think Johannes proposal already nails it. What benefits would be
merged from this proposal? How would they influence the design?

On 04/06/2012 11:41 AM, Johannes Pfau wrote:

Declaring a custom attribute:
-
module std.something;

struct Author
{
string name;
public this(string name)
{
this.name  = name;
}
}
-




Oh the joy of copy and paste ..

struct Annotation  //Throw in all your annotations
{

Variant[] [string] map;

Variant[] opDispatch(string key)()
{
   return map[key];
}

// Single value
void opDispatch(string key, T) (T t )
if ( !isArray!T && !isTuple!T )
{
map[key] ~= to!Variant(t);
return;
 }
// Allow Array and Tuple too
}


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread bls

On 04/06/2012 07:04 AM, Manu wrote:

I think Johannes proposal already nails it. What benefits would be
merged from this proposal? How would they influence the design?

On 04/06/2012 11:41 AM, Johannes Pfau wrote:

Declaring a custom attribute:
-
module std.something;

struct Author
{
string name;
public this(string name)
{
this.name  = name;
}
}
-


Why not being more flexible .. Likewise

struct Annotation  //Throw in all your annotations
{

Variant[] [string] map;

Variant[] opDispatch(string key)()
{
return map[key];
}   

// Single value
Variant[] opDispatch(string key, T) (T t )
if ( !isArray!T && !isTuple!T )
{
index ~= key;
map[key] ~= to!Variant(t);
return map[key];
}   
Array, Tuple
}
well.. I am not sure about CTFE


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer

On Fri, 06 Apr 2012 13:33:33 -0400, Tove  wrote:
I think this proposal pretty much covers what I would expect from  
'custom attributes'... but what about adding a D twist, getting "what we  
annotate" as a template parameter so that one among other things can  
make use of Template Constraints?


Interesting, so something like:

@attribute string defaultName(T)() if(is(typeof(T.init.name))) { return  
T.init.name;}


Not sure how much this gives us, but it definitely feels doable.

-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer

On Fri, 06 Apr 2012 10:46:33 -0400, Timon Gehr  wrote:

Constructors are functions too, and the compiler can run them too. I  
think the implementation should just allow any ctfe-callable symbol to  
be used as an attribute.


This does make sense.  Not having the ctor be an attribute (or the struct  
itself) is an easily-worked around limitation (just create a factory  
function).  It would make sense that you should be able to call a ctor  
just as well as you can call a function, and not have to create a stub  
function that simply calls the ctor.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 12:53:51 -0400, Piotr Szturmaj   
wrote:



Andrej Mitrovic wrote:

On 4/6/12, Piotr Szturmaj  wrote:

Static opCall() should do the trick


But it seems like a roundabout way to work around an implementation
issue just to enable annotations.


What do you mean? You can also initialize structs without default  
contructor:


struct Author { string name = "empty"; }
// struct Author { string name; } - this works too


I think the point is, we should disallow:

@Author int x;

-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj   
wrote:



Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 10:11:32 -0400, Manu  wrote:

On 6 April 2012 16:56, Steven Schveighoffer   
wrote:



On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr 
wrote:

I think this proposal should be merged with Johannes' one.




It is very similar. I think the main distinction is that I focused on
the
fact that the compiler already has a mechanism to check and run CTFE
functions.



Except you're using a function, which I don't follow. How does that  
work?

Where do you actually store the attribute data?
Just attaching any arbitrary thing, in particular, a struct (as in
Johannes
proposal) is far more useful. It also seems much simpler conceptually  
to

me. It's nice when things are intuitive...


You can store a struct, just return it from an attribute function.

e.g.:

@attribute Author author(string name) { return Author(name);}


Compare it to:

struct Author { string name; }

@Author("John Doe") int x;


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.


BTW, if I wasn't trying to demonstrate that you could store structs, I  
would have written:


@attrubte string author(string name) { return name;}

and save the extra bloat associated with declaring another type.  Maybe we  
could even get this someday:


@attribute author(string name) => name;

I just don't see the need to declare a type that can wrap a string.

You could even add this rule:

if @attribute is placed on a struct, its constructor becomes an @attribute  
qualified function with the name of the struct as the attribute name.


Why should we be restricted to only structs? Or any type for that  
matter?


When using __traits(getAttributes, ...) you ask for conrete (struct)  
type and you get it. In case of function you ask for serializable but  
you get a bool.


It's an example.  you can choose any type you want!  I actually just want  
the name of the author, I don't care whether that's a struct, or a string.





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.


Compiler can easily deal with structs too:


I concede this is probably a non-issue.


I also firmly believe that determining what is allowed as attributes
should be opt-in. Just allowing any struct/class/function/etc. would
lead to bizarre declarations.


C# has requirement that attributes are classes that derive from base  
Attribute class. But without that limitation you can do things like:


@Uuid("...")
interface MyIntf { }

without explicitly declaring Uuid as attribute. However, I don't see any  
usage for primitive types:


@5
@"s"
@false


I don't understand what you are saying here.

I think that allowing values of structs, classes and _eventually_ enums  
should be enough.


Any CTFE computed value should suffice.

-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Tove
On Friday, 6 April 2012 at 14:23:51 UTC, Steven Schveighoffer 
wrote:
On Fri, 06 Apr 2012 10:11:32 -0400, Manu  
wrote:


On 6 April 2012 16:56, Steven Schveighoffer 
 wrote:


On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr 
 wrote:


I think this proposal should be merged with Johannes' one.




It is very similar.  I think the main distinction is that I 
focused on the
fact that the compiler already has a mechanism to check and 
run CTFE

functions.



Except you're using a function, which I don't follow. How does 
that work?

Where do you actually store the attribute data?
Just attaching any arbitrary thing, in particular, a struct 
(as in Johannes
proposal) is far more useful. It also seems much simpler 
conceptually to

me. It's nice when things are intuitive...


You can store a struct, just return it from an attribute 
function.


e.g.:

@attribute Author author(string name) { return Author(name);}

Why should we be restricted to only structs?  Or any type for 
that matter?


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.


I also firmly believe that determining what is allowed as 
attributes should be opt-in.  Just allowing any 
struct/class/function/etc. would lead to bizarre declarations.


-Steve


I think this proposal pretty much covers what I would expect from 
'custom attributes'... but what about adding a D twist, getting 
"what we annotate" as a template parameter so that one among 
other things can make use of Template Constraints?





Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Andrej Mitrovic wrote:

On 4/6/12, Piotr Szturmaj  wrote:

Static opCall() should do the trick


But it seems like a roundabout way to work around an implementation
issue just to enable annotations.


What do you mean? You can also initialize structs without default 
contructor:


struct Author { string name = "empty"; }
// struct Author { string name; } - this works too

enum a = Author();
pragma(msg, a.name);
enum b = Author("test");
pragma(msg, b.name);

I don't think default constructors or opCall are _needed_ for annotations.


Well anyway as long as we *get* annotations at some point, all will be fine. :)


I'm sure it will!


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Andrej Mitrovic
On 4/6/12, Piotr Szturmaj  wrote:
> Static opCall() should do the trick

But it seems like a roundabout way to work around an implementation
issue just to enable annotations.

Well anyway as long as we *get* annotations at some point, all will be fine. :)


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Andrej Mitrovic wrote:

On 4/6/12, Piotr Szturmaj  wrote:
struct Author { string name; }


Also, let's not forget the glaring limitation of structs that almost
everyone has ran into: you can't define a default ctor.


Static opCall() should do the trick:

struct Author
{
string name;
static Author opCall()
{
Author a;
a.name = "empty";
return a;
}
}

enum a = Author();
pragma(msg, a.name);


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Andrej Mitrovic
> On 4/6/12, Piotr Szturmaj  wrote:
> struct Author { string name; }

Also, let's not forget the glaring limitation of structs that almost
everyone has ran into: you can't define a default ctor.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Andrej Mitrovic
On 4/6/12, Piotr Szturmaj  wrote:
>> @attribute Author author(string name) { return Author(name);}
>
> Compare it to:
>
> struct Author { string name; }
>
> @Author("John Doe") int x;

I assume we could use templated functions:

struct Author { string name; }
@attribute T temp(T, Args...)(Args args){ return T(args);}
@temp!Author("John Doe") int x;

On 4/6/12, Piotr Szturmaj  wrote:
> Compiler can easily deal with structs too:
>
> enum author = Author("John");
> pragma(msg, author.name);

Just throwing this out there that's semi-related: there's a bug w.r.t.
struct constructors and enums:
http://d.puremagic.com/issues/show_bug.cgi?id=5460


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 18:17, Adam D. Ruppe  wrote:

> On Friday, 6 April 2012 at 15:07:04 UTC, Manu wrote:
>
>> But maybe the function approach has an
>> effect on the simplicity of the expression for a simple attribute, like a
>> single bool?
>>
>
> Meh, it is pretty similar:
>
> struct Serializable { bool yes; }
> bool Serializable(bool yes) { return yes; }
>

Indeed. And with that in mind...


On 6 April 2012 17:56, Piotr Szturmaj  wrote:

> @Uuid("...")
> interface MyIntf { }
>
> without explicitly declaring Uuid as attribute. However, I don't see any
> usage for primitive types:
>
> @5
> @"s"
> @false
>
> I think that allowing values of structs, classes and _eventually_ enums
> should be enough.
>

I totally agree, although I don't know what enum's offer that can't be
equally wrapped in a struct/class? They can probably be skipped as well.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Adam D. Ruppe

On Friday, 6 April 2012 at 15:07:04 UTC, Manu wrote:

But maybe the function approach has an
effect on the simplicity of the expression for a simple 
attribute, like a single bool?


Meh, it is pretty similar:

struct Serializable { bool yes; }
bool Serializable(bool yes) { return yes; }



Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 17:53, Timon Gehr  wrote:

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

The only real difference I see, is at the end of the day, the one level of
indirection (the function call) allows you to create an attribute with a
different name than struct that defines it. Otherwise they would seem to be
functionally equivalent.
Chances are, the creator function would just execute the struct's
constructor internally anyway. But maybe the function approach has an
effect on the simplicity of the expression for a simple attribute, like a
single bool?
I suppose a single bool attribute wouldn't work so well declared the
constructor way, it really does need the name it would inherit from the
creator function...


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Piotr Szturmaj

Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 10:11:32 -0400, Manu  wrote:


On 6 April 2012 16:56, Steven Schveighoffer  wrote:


On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr 
wrote:

I think this proposal should be merged with Johannes' one.




It is very similar. I think the main distinction is that I focused on
the
fact that the compiler already has a mechanism to check and run CTFE
functions.



Except you're using a function, which I don't follow. How does that work?
Where do you actually store the attribute data?
Just attaching any arbitrary thing, in particular, a struct (as in
Johannes
proposal) is far more useful. It also seems much simpler conceptually to
me. It's nice when things are intuitive...


You can store a struct, just return it from an attribute function.

e.g.:

@attribute Author author(string name) { return Author(name);}


Compare it to:

struct Author { string name; }

@Author("John Doe") int x;


Why should we be restricted to only structs? Or any type for that matter?


When using __traits(getAttributes, ...) you ask for conrete (struct) 
type and you get it. In case of function you ask for serializable but 
you get a bool.



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.


Compiler can easily deal with structs too:

enum author = Author("John");
pragma(msg, author.name);


I also firmly believe that determining what is allowed as attributes
should be opt-in. Just allowing any struct/class/function/etc. would
lead to bizarre declarations.


C# has requirement that attributes are classes that derive from base 
Attribute class. But without that limitation you can do things like:


@Uuid("...")
interface MyIntf { }

without explicitly declaring Uuid as attribute. However, I don't see any 
usage for primitive types:


@5
@"s"
@false

I think that allowing values of structs, classes and _eventually_ enums 
should be enough.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Timon Gehr

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.



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.




Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 17:47, Dmitry Olshansky  wrote:

> Looks good to me.
>
> The missing piece is:
>
> >You also need means to enumerate attributes.
>

There are well established patterns for enumerating traits (ie. allMembers
and friends)


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Timon Gehr

On 04/06/2012 03:56 PM, Steven Schveighoffer wrote:

On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr  wrote:


I think this proposal should be merged with Johannes' one.


It is very similar. I think the main distinction is that I focused on
the fact that the compiler already has a mechanism to check and run CTFE
functions.

-Steve


Checking and running are basically the same thing. The compiler can run 
functions that are only partially ctfe-able.


Constructors are functions too, and the compiler can run them too. I 
think the implementation should just allow any ctfe-callable symbol to 
be used as an attribute.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Dmitry Olshansky

Looks good to me.

The missing piece is:

>You also need means to enumerate attributes.

>Andrei


--
Dmitry Olshansky


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 17:23, Steven Schveighoffer  wrote:

> You can store a struct, just return it from an attribute function.
>
> e.g.:
>
> @attribute Author author(string name) { return Author(name);}
>
> Why should we be restricted to only structs?  Or any type for that matter?
>
> 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.
>

Yep, I see now. If this is significantly simpler, then so be it. Whatever
gets it done. This certainly meets my requirements.


I also firmly believe that determining what is allowed as attributes should
> be opt-in.  Just allowing any struct/class/function/etc. would lead to
> bizarre declarations.
>

I see your point, and I also had this thought. I'm on the fence though, not
sure if it's valuable or not.
Does this approach really change that though? It could return anything it
likes, and then it's no different than binding one of those directly.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 17:17, Adam D. Ruppe  wrote:

> On Friday, 6 April 2012 at 14:11:42 UTC, Manu wrote:
>
>> Except you're using a function, which I don't follow.
>>
>
> It is pretty simple: the return value of the function
> is stored in the compiler, the same as all the other
> proposals.
>
> The struct thing is the same, really. You're just calling
> a constructor there instead of a regular function.
>
>
> Really, of the... what five proposals out there now? But
> they are all almost the same. A constructor, a function
> call, an expression, or a field initializor list all
> give the same result - they all return a piece of data,
> which is attached to the declaration in the compiler.
>
> We're just quibbling over details. I say we just forget
> about that and pick one to make this happen.
>
> I barely even care which one right now.
>

Ah okay, I see now. You're just using a creator, instead of a constructor.
Yeah fine, whatever.
I'm not quibbling over details, it just wasn't clear to me at all from your
syntax what it was you were actually doing (see: intuitive).

The only thing I care about is that I can associate an arbitrary data
struct, and ideally, the syntax is intuitive and minimal.
I prefer to use the constructor personally (I think it produces a much
simpler/intuitive syntax), and I also like that the '@attribute' keyword is
not necessary in Johannes version, but I really don't care. Whatever works
best in practise, as long as the basic premise is met.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer

On Fri, 06 Apr 2012 10:11:32 -0400, Manu  wrote:


On 6 April 2012 16:56, Steven Schveighoffer  wrote:

On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr   
wrote:


 I think this proposal should be merged with Johannes' one.




It is very similar.  I think the main distinction is that I focused on  
the

fact that the compiler already has a mechanism to check and run CTFE
functions.



Except you're using a function, which I don't follow. How does that work?
Where do you actually store the attribute data?
Just attaching any arbitrary thing, in particular, a struct (as in  
Johannes

proposal) is far more useful. It also seems much simpler conceptually to
me. It's nice when things are intuitive...


You can store a struct, just return it from an attribute function.

e.g.:

@attribute Author author(string name) { return Author(name);}

Why should we be restricted to only structs?  Or any type for that matter?

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.


I also firmly believe that determining what is allowed as attributes  
should be opt-in.  Just allowing any struct/class/function/etc. would lead  
to bizarre declarations.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Adam D. Ruppe

On Friday, 6 April 2012 at 14:11:42 UTC, Manu wrote:

Except you're using a function, which I don't follow.


It is pretty simple: the return value of the function
is stored in the compiler, the same as all the other
proposals.

The struct thing is the same, really. You're just calling
a constructor there instead of a regular function.


Really, of the... what five proposals out there now? But
they are all almost the same. A constructor, a function
call, an expression, or a field initializor list all
give the same result - they all return a piece of data,
which is attached to the declaration in the compiler.

We're just quibbling over details. I say we just forget
about that and pick one to make this happen.

I barely even care which one right now.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 16:56, Steven Schveighoffer  wrote:

> On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr  wrote:
>
>  I think this proposal should be merged with Johannes' one.
>>
>
> It is very similar.  I think the main distinction is that I focused on the
> fact that the compiler already has a mechanism to check and run CTFE
> functions.
>

Except you're using a function, which I don't follow. How does that work?
Where do you actually store the attribute data?
Just attaching any arbitrary thing, in particular, a struct (as in Johannes
proposal) is far more useful. It also seems much simpler conceptually to
me. It's nice when things are intuitive...


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Manu
On 6 April 2012 16:53, Timon Gehr  wrote:

> I think this proposal should be merged with Johannes' one.
>

I think Johannes proposal already nails it. What benefits would be merged
from this proposal? How would they influence the design?


On 04/06/2012 11:41 AM, Johannes Pfau wrote:
>
>> 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.
>>
>


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer

On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr  wrote:


I think this proposal should be merged with Johannes' one.


It is very similar.  I think the main distinction is that I focused on the  
fact that the compiler already has a mechanism to check and run CTFE  
functions.


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Timon Gehr

I think this proposal should be merged with Johannes' one.

On 04/06/2012 11:41 AM, Johannes Pfau wrote:

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.


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 09:43:37 -0400, Adam D. Ruppe  
 wrote:



On Friday, 6 April 2012 at 13:23:03 UTC, Steven Schveighoffer wrote:


1. Introduce a new compiler-defined attribute @attribute (or @attr or  
something better, the name isn't important).

2. This attribute can *only* be used on a module-level function.


This is a fine time to disallow built-in attribute identifiers.

safe is not a keyword:

int safe() { return 0; }
void main() { if(safe) assert(0); }

That's valid code.

But, @safe already has a meaning.

While int safe() is fine, @atttribute int safe() shouldn't
be.

If it throws an error when it sees that declaration, we're
in business.

@attribute int safe()
Error: attribute identifer safe is reserved for the compiler


Good point, I agree.


3. @attribute functions *must* be CTFE-able.


Can this be statically checked? Since CTFE-able-ness
depends on runtime params and errors, I don't think so.


I thought there were two parts to CTFE:

1. The parameters can be determined at compile-time
2. The function has certain attributes (e.g. all source code available,  
does not access globals, etc.)


I really was referring to part 2, which I assumed was statically  
determined.


This differs from current CTFE-able functions in that the compiler doesn't  
know at declaration whether it's going to be used for CTFE or not.



I'd say this should not be a strict requirement on
the declaration. Just let the CTFE fail when you try
to use it.


If this is the only way to do it, I'm fine with that.

-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Adam D. Ruppe
On Friday, 6 April 2012 at 13:23:03 UTC, Steven Schveighoffer 
wrote:

So here is my proposal:


This is a pretty good one. I can live with it.

Two notes though:

1. Introduce a new compiler-defined attribute @attribute (or 
@attr or something better, the name isn't important).

2. This attribute can *only* be used on a module-level function.


This is a fine time to disallow built-in attribute identifiers.

safe is not a keyword:

int safe() { return 0; }
void main() { if(safe) assert(0); }

That's valid code.

But, @safe already has a meaning.

While int safe() is fine, @atttribute int safe() shouldn't
be.

If it throws an error when it sees that declaration, we're
in business.

@attribute int safe()
Error: attribute identifer safe is reserved for the compiler



3. @attribute functions *must* be CTFE-able.


Can this be statically checked? Since CTFE-able-ness
depends on runtime params and errors, I don't think so.

I'd say this should not be a strict requirement on
the declaration. Just let the CTFE fail when you try
to use it.



Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
On Fri, 06 Apr 2012 09:23:01 -0400, Steven Schveighoffer  
 wrote:


7. One can lookup whether an attribute exists on a symbol using  
__traits(hasAttribute, symbol).
8. One can retrieve the value of the CTFE result using  
__traits(getAttribute, symbol).  If the CTFE function returns void, this  
is a compiler error.


Boy, this was underspecified!

__traits(hasAttribute, attribute, symbol)
__traits(getAttribute, attribute, symbol)

string serialize(T)(const ref T t) if (__traits(hasAttribute,  
serializable) && __traits(getAttribute, serializable))


again:

if (__traits(hasAttribute, serializable, T) && __traits(getAttribute,  
serializable, T))


-Steve


Re: custom attribute proposal (yeah, another one)

2012-04-06 Thread Bernard Helyer
I think this is the sanest proposal I've seen yet. It leverages 
what it needs (CTFE, module look up) without being 
incomprehensible, and is usable at compile time. Two thumbs up.




custom attribute proposal (yeah, another one)

2012-04-06 Thread Steven Schveighoffer
OK, so I woke up this morning to find a huge discussion on attributes, and  
I'd like to once again propose the idea of how to define and use an  
attribute.


I do not like the idea of:

@attr(identifier)

Why?  Because what the hell did we create that "@" syntax for?  I though  
it was to avoid misinterpreting such things as normal symbols, and avoid  
creating new keywords.  Why should the compiler be the only one able to  
use such symbols?


Another thing I don't like is some idea that only a certain type of  
construct can be the identifier.  An attribute should have one requirement  
-- that it can be created/determined at compile time.


So here is my proposal:

1. Introduce a new compiler-defined attribute @attribute (or @attr or  
something better, the name isn't important).

2. This attribute can *only* be used on a module-level function.
3. @attribute functions *must* be CTFE-able.
4. An @attribute function can be used as a user-defined attribute on any  
declaration using the syntax @identifier where identifier is the name of  
the attribute function (subject to normal function lookup rules).  If the  
attribute can be called without parameters, the parentheses are optional.
5. When used on a declaration, that CTFE function is called during  
compile-time, and the result of that function is stored as metadata on  
that symbol.  It does not affect the type of the symbol or transfer to any  
other symbols that are assigned to the value of that declaration (in other  
words, it *cannot* be used as a type constructor).
6. The metadata is stored in a key-value pair, with the key being the  
symbol of the @attribute function, and the value being the result of the  
CTFE function.
7. One can lookup whether an attribute exists on a symbol using  
__traits(hasAttribute, symbol).
8. One can retrieve the value of the CTFE result using  
__traits(getAttribute, symbol).  If the CTFE function returns void, this  
is a compiler error.


And that's it.  We can extend this eventually to storing something in  
TypeInfo, but I'm not sure we need that.  However, I want to stress that  
having runtime type metadata is not a requirement for this proposal.


Example usage:

@attribute bool serializable(bool yesorno = true) { return yesorno; }

unittest {
   // serializable is a normal function also
   assert(serializable() == true);
   assert(serializable(true) == true);
   assert(serializable(false) == false);
}

@serializable struct MyType
{
   int x;
   int y;
   @serializable(false) int z;
}

string serialize(T)(const ref T t) if (__traits(hasAttribute,  
serializable) && __traits(getAttribute, serializable))

{
  // serialize each field.  Skip any fields that are marked as  
serializable == false

}

-Steve