digitalmars.D - custom attribute proposal (yeah, another one)
- Steven Schveighoffer (58/58) Apr 06 2012 OK, so I woke up this morning to find a huge discussion on attributes, a...
- Bernard Helyer (3/3) Apr 06 2012 I think this is the sanest proposal I've seen yet. It leverages
- Adam D. Ruppe (21/26) Apr 06 2012 This is a pretty good one. I can live with it.
- Steven Schveighoffer (13/35) Apr 06 2012 Good point, I agree.
- Steven Schveighoffer (9/16) Apr 06 2012 Boy, this was underspecified!
- Timon Gehr (2/35) Apr 06 2012
- Steven Schveighoffer (5/6) Apr 06 2012 It is very similar. I think the main distinction is that I focused on t...
- Manu (6/12) Apr 06 2012 Except you're using a function, which I don't follow. How does that work...
- Adam D. Ruppe (14/15) Apr 06 2012 It is pretty simple: the return value of the function
- Manu (11/27) Apr 06 2012 Ah okay, I see now. You're just using a creator, instead of a constructo...
- Steven Schveighoffer (12/30) Apr 06 2012 You can store a struct, just return it from an attribute function.
- Manu (8/17) Apr 06 2012 Yep, I see now. If this is significantly simpler, then so be it. Whateve...
- Timon Gehr (5/9) Apr 06 2012 A restriction to only structs is not a restriction because structs can
- Manu (12/25) Apr 06 2012 The only real difference I see, is at the end of the day, the one level ...
- Adam D. Ruppe (4/7) Apr 06 2012 Meh, it is pretty similar:
- Manu (5/22) Apr 06 2012 Indeed. And with that in mind...
- Mafi (15/22) Apr 06 2012 There's one difference I think.
- Steven Schveighoffer (17/41) Apr 06 2012 I acknowledge this limitation. But we can also overload functions:
- Mafi (5/30) Apr 06 2012 The second possibility looks good. Especially because the lack of
- deadalnix (3/23) Apr 07 2012 This is adding code just for the pleasure of adding more code. Why wan't...
- Steven Schveighoffer (9/34) Apr 09 2012 't =
- Jacob Carlborg (5/8) Apr 07 2012 Isn't "square" the name of the attribute? In that case you would use:
- Steven Schveighoffer (11/19) Apr 09 2012 The argument was to use the name of the type returned as the attribute
- Jacob Carlborg (4/14) Apr 09 2012 Aha, I see.
- Marco Leise (38/51) Apr 08 2012 r?
- Piotr Szturmaj (21/52) Apr 06 2012 Compare it to:
- Andrej Mitrovic (9/16) Apr 06 2012 I assume we could use templated functions:
- Andrej Mitrovic (2/4) Apr 06 2012 Also, let's not forget the glaring limitation of structs that almost
- Piotr Szturmaj (14/18) Apr 06 2012 Static opCall() should do the trick:
- Andrej Mitrovic (4/5) Apr 06 2012 But it seems like a roundabout way to work around an implementation
- Piotr Szturmaj (11/16) Apr 06 2012 What do you mean? You can also initialize structs without default
- Steven Schveighoffer (5/15) Apr 06 2012 I think the point is, we should disallow:
- Jacob Carlborg (4/10) Apr 07 2012 Why?
- Steven Schveighoffer (6/17) Apr 09 2012 I misspoke. The person who implemented the @Author attribute probably
- Marco Leise (10/31) Apr 09 2012 Yes, when libraries start to offer attributes, their authors likely want...
- Steven Schveighoffer (22/80) Apr 06 2012 so now I must define a type for every attribute? I'd rather just define...
- Piotr Szturmaj (27/90) Apr 06 2012 I don't see advantage of functions here, twenty of them is also a bloat....
- Steven Schveighoffer (18/60) Apr 06 2012 Unused function do not make it into the EXE.
- Piotr Szturmaj (15/81) Apr 06 2012 Ok, but how do you filter that and pass the result to another template?
- Jacob Carlborg (4/8) Apr 07 2012 void ?
- Piotr Szturmaj (3/9) Apr 07 2012 I know that's the answer, but how would you store void, and get it from
- Jacob Carlborg (5/16) Apr 07 2012 The compiler would only store that the attribute is attached to the
- Steven Schveighoffer (17/46) Apr 09 2012 Their TypeInfo_Struct is. If they are compiled in their own module, the...
- Johannes Pfau (52/65) Apr 07 2012 But as long as you mark attribute structs in some special way
- deadalnix (7/57) Apr 07 2012 For basic type :
- Jacob Carlborg (12/16) Apr 07 2012 If we want to be able to pass a key-value list to the attribute, I think...
- Steven Schveighoffer (9/18) Apr 09 2012 What if they have nothing to do with each other? What I'm getting at is...
- Tove (6/45) Apr 06 2012 I think this proposal pretty much covers what I would expect from
- Steven Schveighoffer (6/10) Apr 06 2012 Interesting, so something like:
- Tove (5/16) Apr 06 2012 yes, exactly... well, once library designers start getting
- Piotr Szturmaj (2/11) Apr 06 2012 See also: http://forum.dlang.org/post/jlmtcv$v09$1@digitalmars.com
- Steven Schveighoffer (6/20) Apr 06 2012 Excellent point, passing the symbol being annotated (probably should be ...
- Piotr Szturmaj (10/15) Apr 06 2012 Yes, I forgot to add "alias". I think this is the best approach to
- Timon Gehr (6/12) Apr 06 2012 Checking and running are basically the same thing. The compiler can run
- Steven Schveighoffer (7/10) Apr 06 2012 This does make sense. Not having the ctor be an attribute (or the struc...
- Manu (4/45) Apr 06 2012 I think Johannes proposal already nails it. What benefits would be merge...
- bls (21/36) Apr 06 2012 Why not being more flexible .. Likewise
- bls (18/37) Apr 06 2012 Oh the joy of copy and paste ..
- Jacob Carlborg (4/23) Apr 07 2012 Variant yet again. What with this Variant all the time.
- Dmitry Olshansky (4/6) Apr 06 2012 --
- Manu (3/6) Apr 06 2012 There are well established patterns for enumerating traits (ie. allMembe...
- David Gileadi (4/7) Apr 06 2012 There may be a good reason why it's not supported, but in Java I've
- deadalnix (3/61) Apr 06 2012 The struct proposal from previous thread was superior because it provide...
- Kapps (19/32) Apr 06 2012 Either this or the one that's the same just with structs is the
- deadalnix (2/6) Apr 07 2012 Then put the attribute at type declaration, not where it is used.
- deadalnix (4/8) Apr 07 2012 If the type isn't used at runtime, the compiler should be able to remove...
- Kapps (4/16) Apr 07 2012 This is not possible currently. The TypeInfo is required at
- deadalnix (2/16) Apr 07 2012 Object.factory is limited to classes IIRC.
- Jacob Carlborg (4/7) Apr 07 2012 Object.factory can only create instances of classes.
- Manu (12/44) Apr 07 2012 Generating a struct for an attribute is fine. It's not like you go on
- Kapps (9/28) Apr 07 2012 The calling methods is a valid point, however the method can
- Manu (3/27) Apr 07 2012 Yeah I'm happy either way. At the end of the day, I guess whoever actual...
- Jacob Carlborg (5/13) Apr 07 2012 This can't be done for structs?
- Steven Schveighoffer (12/23) Apr 09 2012 functions are easier for the linker to deal with. The main point here i...
- Jacob Carlborg (4/8) Apr 09 2012 Using any callable CTFE symbol would make sense.
- foobar (10/10) Apr 07 2012 After reading the thread my vote goes to the struct proposal.
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
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
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 compiler3. 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
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:Good point, I agree.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 compilerI 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.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.If this is the only way to do it, I'm fine with that. -Steve
Apr 06 2012
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
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
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
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.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...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.
Apr 06 2012
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
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: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.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
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: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. -SteveOn 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.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...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.
Apr 06 2012
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 shouldbe 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
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
On 6 April 2012 17:53, Timon Gehr <timon.gehr gmx.ch> wrote:On 04/06/2012 04:23 PM, Steven Schveighoffer wrote: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...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 knowshow 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
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
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:Indeed. And with that in mind... On 6 April 2012 17:56, Piotr Szturmaj <bncrbme jadamspam.pl> 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; }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
Am 06.04.2012 17:17, schrieb Adam D. Ruppe:On Friday, 6 April 2012 at 15:07:04 UTC, Manu 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. 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. MafiBut 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
On Fri, 06 Apr 2012 14:23:45 -0400, Mafi <mafi example.org> wrote:Am 06.04.2012 17:17, schrieb Adam D. Ruppe: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(); -SteveOn Friday, 6 April 2012 at 15:07:04 UTC, Manu 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. 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.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
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(); -SteveThe second possibility looks good. Especially because the lack of attribute on square disallows square. Mafi
Apr 06 2012
Le 06/04/2012 22:46, Mafi a écrit :This is adding code just for the pleasure of adding more code. Why wan't I construct Area directly as attribute ?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(); -SteveThe second possibility looks good. Especially because the lack of attribute on square disallows square. Mafi
Apr 07 2012
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 :'t =This is adding code just for the pleasure of adding more code. Why wan=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(); -SteveThe second possibility looks good. Especially because the lack of attribute on square disallows square. MafiI 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
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
On Sat, 07 Apr 2012 10:11:16 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-04-06 20:52, 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. -SteveAlso, 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)
Apr 09 2012
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. -SteveAha, I see. -- /Jacob Carlborg
Apr 09 2012
Am Fri, 06 Apr 2012 16:53:56 +0200 schrieb Timon Gehr <timon.gehr gmx.ch>:On 04/06/2012 04:23 PM, Steven Schveighoffer wrote:r?Why should we be restricted to only structs? Or any type for that matte=+1=20 A restriction to only structs is not a restriction because structs can=20 have arbitrary field types.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 MarcoThe 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.
Apr 08 2012
Steven Schveighoffer wrote:On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> wrote:Compare it to: struct Author { string name; } Author("John Doe") int x;On 6 April 2012 16:56, 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);}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.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...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.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
On 4/6/12, Piotr Szturmaj <bncrbme jadamspam.pl> wrote: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:attribute Author author(string name) { return Author(name);}Compare it to: struct Author { string name; } Author("John Doe") int x;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
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
Andrej Mitrovic wrote: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);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
On 4/6/12, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Static opCall() should do the trickBut 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
Andrej Mitrovic wrote:On 4/6/12, Piotr Szturmaj<bncrbme jadamspam.pl> wrote: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.Static opCall() should do the trickBut 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. :)I'm sure it will!
Apr 06 2012
On Fri, 06 Apr 2012 12:53:51 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Andrej Mitrovic wrote:I think the point is, we should disallow: Author int x; -SteveOn 4/6/12, Piotr Szturmaj<bncrbme jadamspam.pl> wrote:What do you mean? You can also initialize structs without default contructor: struct Author { string name = "empty"; } // struct Author { string name; } - this works tooStatic opCall() should do the trickBut it seems like a roundabout way to work around an implementation issue just to enable annotations.
Apr 06 2012
On 2012-04-06 19:37, Steven Schveighoffer wrote:On Fri, 06 Apr 2012 12:53:51 -0400, Piotr SzturmajWhy? -- /Jacob Carlborgstruct Author { string name = "empty"; } // struct Author { string name; } - this works tooI think the point is, we should disallow: Author int x; -Steve
Apr 07 2012
On Sat, 07 Apr 2012 10:00:19 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-04-06 19:37, Steven Schveighoffer wrote: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. -SteveOn Fri, 06 Apr 2012 12:53:51 -0400, Piotr SzturmajWhy?struct Author { string name = "empty"; } // struct Author { string name; } - this works tooI think the point is, we should disallow: Author int x; -Steve
Apr 09 2012
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: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". -- MarcoOn 2012-04-06 19:37, Steven Schveighoffer wrote: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. -SteveOn Fri, 06 Apr 2012 12:53:51 -0400, Piotr SzturmajWhy?struct Author { string name = "empty"; } // struct Author { string name; } - this works tooI think the point is, we should disallow: Author int x; -Steve
Apr 09 2012
On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote: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. 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.On Fri, 06 Apr 2012 10:11:32 -0400, Manu <turkeyman gmail.com> wrote:Compare it to: struct Author { string name; } Author("John Doe") int x;On 6 April 2012 16:56, 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);}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.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...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.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.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.I concede this is probably a non-issue.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 don't understand what you are saying here.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" falseI think that allowing values of structs, classes and _eventually_ enums should be enough.Any CTFE computed value should suffice. -Steve
Apr 06 2012
Steven Schveighoffer wrote:On Fri, 06 Apr 2012 10:56:19 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:So declaration is always needed, no matter what attribute is.Steven Schveighoffer wrote:so now I must define a type for every attribute? I'd rather just define a function.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;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.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.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.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."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 concede this is probably a non-issue.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 don't understand what you are saying here.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" falseI 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.I think that allowing values of structs, classes and _eventually_ enums should be enough.Any CTFE computed value should suffice.
Apr 06 2012
On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Steven Schveighoffer wrote:Unused function do not make it into the EXE.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.foreach(name, value; __traits(getAttributes, symbol)) {...} hereby added to the proposal.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.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.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 ;)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.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.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.Again, see point above about not naming variables.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.not have the compile-time power that D does. -Steve
Apr 06 2012
Steven Schveighoffer wrote:On Fri, 06 Apr 2012 15:03:39 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Are unused structs compiled into EXE?Steven Schveighoffer wrote:Unused function do not make it into the EXE.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.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.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.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.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.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.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).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 ;)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.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()?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.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 didn't state that we shouldn't use compile-time :)Again, see point above about not naming variables.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.not have the compile-time power that D does.
Apr 06 2012
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
Jacob Carlborg wrote:On 2012-04-07 00:40, Piotr Szturmaj wrote:I know that's the answer, but how would you store void, and get it from __traits(getAttributes) ?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 ?
Apr 07 2012
On 2012-04-07 16:30, Piotr Szturmaj wrote:Jacob Carlborg wrote:The compiler would only store that the attribute is attached to the declaration. In this case only "hasAttribute" is of interest. -- /Jacob CarlborgOn 2012-04-07 00:40, Piotr Szturmaj wrote:I know that's the answer, but how would you store void, and get it from __traits(getAttributes) ?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 ?
Apr 07 2012
On Fri, 06 Apr 2012 18:40:29 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Steven Schveighoffer wrote: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.Unused function do not make it into the EXE.Are unused structs compiled into EXE?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.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.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.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.The compiler can "build" a struct if it wants to, it reduces to the equivalent problem.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()?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.compile-time facilities didn't allow them a better solution like mine ;) -SteveI didn't state that we shouldn't use compile-time :)not have the compile-time power that D does.
Apr 09 2012
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: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.Steven Schveighoffer wrote:Unused function do not make it into the EXE.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.
Apr 07 2012
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
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
On Sat, 07 Apr 2012 09:59:27 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-04-06 19:36, Steven Schveighoffer wrote: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.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.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
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: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?On 6 April 2012 16:56, 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. 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. -SteveOn 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.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...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.
Apr 06 2012
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
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:yes, exactly... well, once library designers start getting creative, one of the immediate benefits would be, easy to understand error-messages.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
Steven Schveighoffer wrote:On Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> wrote:See also: http://forum.dlang.org/post/jlmtcv$v09$1 digitalmars.comI 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.
Apr 06 2012
On Fri, 06 Apr 2012 15:06:47 -0400, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Steven Schveighoffer wrote: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! -SteveOn Fri, 06 Apr 2012 13:33:33 -0400, Tove <tove fransson.se> wrote:See also: http://forum.dlang.org/post/jlmtcv$v09$1 digitalmars.comI 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.
Apr 06 2012
Steven Schveighoffer wrote:On Fri, 06 Apr 2012 15:06:47 -0400, Piotr SzturmajYes, 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); }See also: http://forum.dlang.org/post/jlmtcv$v09$1 digitalmars.comExcellent 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!
Apr 06 2012
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: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.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
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
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
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
On 04/06/2012 10:51 AM, bls wrote:On 04/06/2012 07:04 AM, Manu wrote: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 }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; } } ---------
Apr 06 2012
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 CTFEVariant yet again. What with this Variant all the time. -- /Jacob Carlborg
Apr 07 2012
Looks good to me. The missing piece is:You also need means to enumerate attributes.Andrei-- Dmitry Olshansky
Apr 06 2012
On 6 April 2012 17:47, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:Looks good to me. The missing piece is:There are well established patterns for enumerating traits (ie. allMembers and friends)You also need means to enumerate attributes.
Apr 06 2012
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
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 } -SteveThe struct proposal from previous thread was superior because it provide similar capability without as much language change.
Apr 06 2012
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
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
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
On Saturday, 7 April 2012 at 11:13:54 UTC, deadalnix wrote:Le 07/04/2012 05:29, Kapps a écrit :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.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
Le 07/04/2012 13:32, Kapps a écrit :On Saturday, 7 April 2012 at 11:13:54 UTC, deadalnix wrote:Object.factory is limited to classes IIRC.Le 07/04/2012 05:29, Kapps a écrit :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.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
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
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: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.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 07 2012
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
On 7 April 2012 14:35, Kapps <opantm2+spam gmail.com> wrote:On Saturday, 7 April 2012 at 11:25:15 UTC, Manu wrote:Yeah I'm happy either way. At the end of the day, I guess whoever actually implements the feature will just follow their preference ;)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
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
On Sat, 07 Apr 2012 12:48:00 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-04-07 05:29, Kapps wrote:functions are easier for the linker to deal with. The main point here is, no TypeInfo needed.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.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. -Steve2) 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?
Apr 09 2012
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
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