www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - custom attribute proposal (yeah, another one)

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Apr 06 2012
next sibling parent "Bernard Helyer" <b.helyer gmail.com> writes:
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.
Apr 06 2012
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Apr 06 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 09:43:37 -0400, Adam D. Ruppe  
<destructionator gmail.com> 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
Apr 06 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 09:23:01 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> 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
Apr 06 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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;
 ---------



 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.
Apr 06 2012
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch> 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
Apr 06 2012
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 16:56, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch> 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...
Apr 06 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Apr 06 2012
parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 17:17, Adam D. Ruppe <destructionator gmail.com> 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.
Apr 06 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> wrote:

 On 6 April 2012 16:56, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch>  
 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
Apr 06 2012
next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 17:23, Steven Schveighoffer <schveiguy yahoo.com> 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.
Apr 06 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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.
Apr 06 2012
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 17:53, Timon Gehr <timon.gehr gmx.ch> 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...
Apr 06 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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; }
Apr 06 2012
next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 18:17, Adam D. Ruppe <destructionator gmail.com> 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 <bncrbme jadamspam.pl> 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.
Apr 06 2012
prev sibling parent reply Mafi <mafi example.org> writes:
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
Apr 06 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 14:23:45 -0400, Mafi <mafi example.org> 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
Apr 06 2012
next sibling parent reply Mafi <mafi example.org> writes:
Am 06.04.2012 20:52, schrieb Steven Schveighoffer:
 On Fri, 06 Apr 2012 14:23:45 -0400, Mafi <mafi example.org> 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
Apr 06 2012
parent reply deadalnix <deadalnix gmail.com> writes:
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 ?
Apr 07 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 07 Apr 2012 07:26:26 -0400, deadalnix <deadalnix gmail.com> wrot=
e:

 Le 06/04/2012 22:46, Mafi a =C3=A9crit :
 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
Apr 09 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 07 Apr 2012 10:11:16 -0400, Jacob Carlborg <doob me.com> 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
Apr 09 2012
parent Jacob Carlborg <doob me.com> writes:
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
Apr 09 2012
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
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 matte=
r?

=20
 A restriction to only structs is not a restriction because structs can=20
 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.
=20 It is exactly the same amount of work because CTFE is able to execute=20 struct constructors.
Yep. Well, in the end the older idea of attributes =3D=3D structs/classes i= s - 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 basi= c types). IDEs can work with this proposal. And if we have to prepend attr= ibute 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 "eve= rything is an object" (or struct) with his idea,=20 I prefer structs-only over functions, because we could augment these struct= s with compiler recognized methods/fields at a later point. Think of the ra= nge interface here, which is implicit. Some examples: attribute struct MyAttribute { // this attribute-struct is allowed multiple times on a symbol enum bool allowMultiple =3D true; // cannot be used on classes, but structs, methods and fields enum uint appliesTo =3D Fields | Methods | Structs; // Run any action in context of the filled attribute structure and=20 // the type it is applied to. With CTFE I/O, it could generate // binaries or text files with bindings. void onInvokation(T)() { =E2=80=A6 } void invariant() { static assert(author, "Author must be given.") } string author; string email =3D "no email; } MyAttribute(author =3D "Some Name", email =3D "some email") MyAttribute(author =3D "Someone Else", email =3D "else email") struct Test { =E2=80=A6 } 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. --=20 Marco
Apr 08 2012
prev sibling next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> wrote:

 On 6 April 2012 16:56, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch>
 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.
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.
Apr 06 2012
next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/6/12, Piotr Szturmaj <bncrbme jadamspam.pl> 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 <bncrbme jadamspam.pl> 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
Apr 06 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
 On 4/6/12, Piotr Szturmaj <bncrbme jadamspam.pl> 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.
Apr 06 2012
parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Andrej Mitrovic wrote:
 On 4/6/12, Piotr Szturmaj<bncrbme jadamspam.pl>  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);
Apr 06 2012
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/6/12, Piotr Szturmaj <bncrbme jadamspam.pl> 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. :)
Apr 06 2012
parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Andrej Mitrovic wrote:
 On 4/6/12, Piotr Szturmaj<bncrbme jadamspam.pl>  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!
Apr 06 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 12:53:51 -0400, Piotr Szturmaj <bncrbme jadamspam.pl>  
wrote:

 Andrej Mitrovic wrote:
 On 4/6/12, Piotr Szturmaj<bncrbme jadamspam.pl>  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
Apr 06 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Apr 09 2012
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 09 Apr 2012 09:13:51 -0400
schrieb "Steven Schveighoffer" <schveiguy yahoo.com>:

 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
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. - 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
Apr 09 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj <bncrbme jadamspam.pl>  
wrote:

 Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> wrote:

 On 6 April 2012 16:56, Steven Schveighoffer <schveiguy yahoo.com>  
 wrote:

 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch>
 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.
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
Apr 06 2012
next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj
 <bncrbme jadamspam.pl> 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.
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.
Apr 06 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj <bncrbme jadamspam.pl>  
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.

not have the compile-time power that D does. -Steve
Apr 06 2012
next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj
 <bncrbme jadamspam.pl> 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.

not have the compile-time power that D does.
I didn't state that we shouldn't use compile-time :)
Apr 06 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
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) ?
Apr 07 2012
parent Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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.

not have the compile-time power that D does.
I didn't state that we shouldn't use compile-time :)
compile-time facilities didn't allow them a better solution like mine ;) -Steve
Apr 09 2012
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 06 Apr 2012 16:33:21 -0400
schrieb "Steven Schveighoffer" <schveiguy yahoo.com>:

 On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj
 <bncrbme jadamspam.pl> 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.
Apr 07 2012
parent deadalnix <deadalnix gmail.com> writes:
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.
Apr 07 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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 = "john doe.com") struct Foo {} BTW, could both structs and functions be allowed? -- /Jacob Carlborg
Apr 07 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Apr 09 2012
prev sibling parent reply "Tove" <tove fransson.se> writes:
On Friday, 6 April 2012 at 14:23:51 UTC, Steven Schveighoffer 
wrote:
 On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> 
 wrote:

 On 6 April 2012 16:56, Steven Schveighoffer 
 <schveiguy yahoo.com> wrote:

 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr 
 <timon.gehr gmx.ch> 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?
Apr 06 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> 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
Apr 06 2012
next sibling parent "Tove" <tove fransson.se> writes:
On Friday, 6 April 2012 at 17:44:25 UTC, Steven Schveighoffer 
wrote:
 On Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> 
 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.
Apr 06 2012
prev sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> 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
Apr 06 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 15:06:47 -0400, Piotr Szturmaj <bncrbme jadamspam.pl>  
wrote:

 Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> 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
Apr 06 2012
parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
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); }
Apr 06 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 03:56 PM, Steven Schveighoffer wrote:
 On Fri, 06 Apr 2012 09:53:59 -0400, Timon Gehr <timon.gehr gmx.ch> 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.
Apr 06 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 10:46:33 -0400, Timon Gehr <timon.gehr gmx.ch> 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
Apr 06 2012
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 16:53, Timon Gehr <timon.gehr gmx.ch> 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;
 ---------



 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.
Apr 06 2012
parent reply bls <bizprac orange.fr> writes:
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 <http://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
Apr 06 2012
next sibling parent bls <bizprac orange.fr> writes:
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 <http://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 }
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
Looks good to me.

The missing piece is:

You also need means to enumerate attributes.
Andrei
-- Dmitry Olshansky
Apr 06 2012
parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 17:47, Dmitry Olshansky <dmitry.olsh gmail.com> 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)
Apr 06 2012
prev sibling next sibling parent David Gileadi <gileadis NSPMgmail.com> writes:
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.
Apr 06 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
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.
Apr 06 2012
prev sibling next sibling parent reply "Kapps" <opantm2+spam gmail.com> writes:
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.
Apr 06 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
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.
Apr 07 2012
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
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.
Apr 07 2012
parent reply "Kapps" <opantm2+spam gmail.com> writes:
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.
Apr 07 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
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.
Apr 07 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On 7 April 2012 06:29, Kapps <opantm2+spam gmail.com> 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.
Apr 07 2012
parent reply "Kapps" <opantm2+spam gmail.com> writes:
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.
Apr 07 2012
parent Manu <turkeyman gmail.com> writes:
On 7 April 2012 14:35, Kapps <opantm2+spam gmail.com> 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 ;)
Apr 07 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 07 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 07 Apr 2012 12:48:00 -0400, Jacob Carlborg <doob me.com> 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
Apr 09 2012
parent Jacob Carlborg <doob me.com> writes:
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
Apr 09 2012
prev sibling parent "foobar" <foo bar.com> writes:
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.
Apr 07 2012