Proposal: user defined attributes
On the ride over here today, I had a thought that I think neatly solves the user defined attribute question. enum Serializable { yes, no } @note(Serializable.yes) int a; We introduce two new things to the language: 1) the @note(expression) attribute. You can put as many "notes" on a declaration as you want by simply listing them. The expression inside is appended to a list on the declaration. This would be valid on variables, functions, function parameters, struct members, etc. 2) __traits(getNotes, decl). This returns a tuple of all the note expressions. foreach(i, exp; __traits(getNotes, a)) { static assert(is(typeof(exp) == Serializable); static assert(exp == Serializable.yes); } This simple extension to the language enables libraries, using existing traits to navigate symbols, to get additional information about things and implement it however. The lack of user defined attributes is D's biggest missed opportunity right now, and I think this simple proposal will plug that hole. Previous user-defined attribute proposals have had counter arguments like these: 1) how do you define what is and is not a valid attribute? Here, the answer is pretty simple: you can put whatever notes you want on the thing. Whether the library uses it or not is up to it. It has to be a valid type - so the compiler will catch typos and whatnot - but it doesn't have to be used unless you ask for it. 2) OK, how do you namespace things so different libraries don't get different results? That's where the beauty of the expression type comes in: D already has namespaces. foo.Serializable != bar.Serializable, so there's no conflict. We simply declare types. The enum X {yes, no} pattern is already common in Phobos, and is also the best way to express a bool condition here. (Technically, @note(true) would compile, but it'd be much less useful than declaring a name for the note too, with an enum.) Name conflicts is a problem already solved by the language. 3) Can we have shared attributes, with declared names so people know what to use in their own libraries? Yes, we could add some to std.traits or make a new std.notes that declare some common items as enums. Though, I think having the types declared in the modules that use them is generally more useful. But, again, the library problem is already solved, and we're just using that! I think this is a winner... and I think I can do it in the compiler in less time than it will take to convince git to give me a clean pull request. Am I missing anything?
Re: Proposal: user defined attributes
On 16 March 2012 15:35, Adam D. Ruppe wrote: > @note(Serializable.yes) int a; > Surely the term you're looking for here is @annotate(...) ? This simple extension to the language enables libraries, > using existing traits to navigate symbols, to get > additional information about things and implement it > however. > > The lack of user defined attributes is D's biggest missed > opportunity right now, and I think this simple proposal > will plug that hole. > I agree it's a very big hole against popular competing languages (Java, C#). Previous user-defined attribute proposals have had counter > arguments like these: > > 1) how do you define what is and is not a valid attribute? > > Here, the answer is pretty simple: you can put whatever notes > you want on the thing. Whether the library uses it or not > is up to it. > What if you want to annotate with a variable? Each instance may need to hold some attribute state. This is extremely common, particularly in serialisation systems which typically perform lazy updates, and need some additional state for that. > 2) OK, how do you namespace things so different libraries don't > get different results? > Surely this is just as easy: @modulename.attribute int myThing; > Am I missing anything? > I think it only solves half the problem. There are certainly cases where you just want to annotate with some sort of tag, so you can know to do something special in this thing's case, but there are also times where you want to associate some variable data with each instance. Perhaps that's the key distinction between 'annotation' and a 'custom attributes' .. an annotation this way is a shared compile time constant, associating with its type info, as you suggest. A custom attribute is an instance-specific association vontaining variable data. I'd suggest that @annotate(someEnum) could work effectively just as you suggest, but it doesn't fill the requirement for custom attributes, which could be implemented separately, something like: attribute myAttribute { this(int something); bool bNeedsAttention; property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } } @myAttribute(10) int thing; thing.refresh = true;
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 14:11:35 UTC, Manu wrote: Surely the term you're looking for here is @annotate(...) ? Meh, I don't care that much about names. I went with "note" anticipating people would complain about @add_user_defined_attribute() being too long :) What if you want to annotate with a variable? That *might* work because a variable is an expression too. I'm not sure though. Will probably have to implement to know for sure. Of course, a constant can be represented as a struct for name and value: struct Description { string s; } @note(Description("yada yada yada")) int a; Surely this is just as easy: @modulename.attribute int myThing; Yeah, I think so. I remember this being a counterpoint last time we talked about it, but I don't recall the specific argument made. Perhaps that's the key distinction between 'annotation' and a 'custom attributes' .. an annotation this way is a shared compile time constant, associating with its type info, as you suggest. A custom attribute is an instance-specific association vontaining variable data. Yeah, "annotation" might be the better word. That's what I want here, but too late to change the subject name now. attribute myAttribute I think this could be done as a struct, but I haven't used this kind of attribute at all so not sure... But what I'm thinking is: struct myAttribute(Type) { Type value; alias value this; bool bNeedsAttention; @property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } } myAttribute!int thing; thing.refresh = true; and thing can be substituted for an int anywhere else.
Re: Proposal: user defined attributes
On 16 March 2012 16:51, Adam D. Ruppe wrote: > On Friday, 16 March 2012 at 14:11:35 UTC, Manu wrote: > >> Surely the term you're looking for here is @annotate(...) ? >> > > Meh, I don't care that much about names. I went > with "note" anticipating people would complain about > @add_user_defined_attribute() being too long :) > > > > What if you want to annotate with a variable? >> > > That *might* work because a variable is an expression too. > I'm not sure though. Will probably have to implement to > know for sure. > > Of course, a constant can be represented as a struct > for name and value: > > struct Description { string s; } > > @note(Description("yada yada yada")) int a; > > > > Surely this is just as easy: @modulename.attribute int myThing; >> > > Yeah, I think so. I remember this being a counterpoint > last time we talked about it, but I don't recall the > specific argument made. > > > Perhaps that's the key distinction between 'annotation' and a 'custom >> attributes' .. an annotation this way is a shared compile time constant, >> associating with its type info, as you suggest. A custom attribute is an >> instance-specific association vontaining variable data. >> > > Yeah, "annotation" might be the better word. That's > what I want here, but too late to change the subject name > now. > > > attribute myAttribute >> > > I think this could be done as a struct, but I haven't > used this kind of attribute at all so not sure... > > But what I'm thinking is: > > struct myAttribute(Type) { > Type value; > alias value this; > > bool bNeedsAttention; > @property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } > } > > myAttribute!int thing; > thing.refresh = true; > > and thing can be substituted for an int anywhere else. > Interesting approach, how will that affect 'thing's type?
Re: Proposal: user defined attributes
Another argument against would be "can we do this in the language today?" And the answer is "sort of, but not really": void a(@note(...) int arg) {} You could perhaps do something like: void a(int arg) {} mixin("enum " ~ a.mangleof ~ "_arg = " ~ ...); and then get the listing by looking at allMembers and comparing the name... but, it gets messy fast - the attribute is somewhat far from the declaration, so I betcha it will get out of sync. Getting the attribute on param 0 too would consist of using stringof tricks to get the name, then mixing it in to get that variable. This isn't a proper tuple either - more care would be needed to handle multiple notes. So, you could make it work, but it is hideous, fragile, and probably less useful even if you look past that. I've seen some nice implementations of struct level annotations, using mixin templates, but the killer feature for me, personally, is putting it on function parameters as well. I think the language addition (which breaks nothing existing today; it is purely additive) is necessary to get something generally useful, not just useful in a few cases.
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 15:10:06 UTC, Manu wrote: Interesting approach, how will that affect 'thing's type? It will strictly be myAttribute!int, but alias this means that you can pass it anywhere an int is expected too (and assign ints to it all the same). Check it: void cool(int a) {} void main() { myAttribute!int thing; thing.refresh = true; thing = 10; // we can assign ints to it, like if it was an int assert(thing.bNeedsAttention); // should be unchanged int a = thing; // no problem, thing is usable as an int assert(a == 10); cool(thing); // ditto }
Re: Proposal: user defined attributes
On 16 March 2012 17:14, Adam D. Ruppe wrote: > On Friday, 16 March 2012 at 15:10:06 UTC, Manu wrote: > >> Interesting approach, how will that affect 'thing's type? >> > > It will strictly be myAttribute!int, but alias this > means that you can pass it anywhere an int is expected > too (and assign ints to it all the same). > > Check it: > > void cool(int a) {} > void main() { > >myAttribute!int thing; >thing.refresh = true; > >thing = 10; // we can assign ints to it, like if it was an int >assert(thing.bNeedsAttention); // should be unchanged > >int a = thing; // no problem, thing is usable as an int >assert(a == 10); > >cool(thing); // ditto > } > I can see that it might work nicely in very simple cases, but it could get nasty in complex constructs. If some template tries to take the typeof for instance, now I'm cloning the attributes functionality too, which I don't think is desirable...
Re: Proposal: user defined attributes
Adam D. Ruppe wrote: On the ride over here today, I had a thought that I think neatly solves the user defined attribute question. enum Serializable { yes, no } @note(Serializable.yes) int a; This is just enum. If you use struct or class attributes (like in C#) then direct @Struct(constructor args..) might be better. Moreover, structs and classes may have special member which validates attribute target: struct MyAttribute { template canAttach(alias Symbol) { // attribute is only valid on structs and // may be used only once per symbol enum canAttach = is(Symbol == struct) && !__traits(hasNotes, Symbol); } } It should be automatically evaluated by the compiler after attribute is attached. Alternatively it may be written like this: template validate(alias Symbol) { static assert(is(Symbol == struct), "MyAttribute must be used with structs"); } We introduce two new things to the language: 1) the @note(expression) attribute. You can put as many "notes" on a declaration as you want by simply listing them. The expression inside is appended to a list on the declaration. This would be valid on variables, functions, function parameters, struct members, etc. 2) __traits(getNotes, decl). This returns a tuple of all the note expressions. foreach(i, exp; __traits(getNotes, a)) { static assert(is(typeof(exp) == Serializable); static assert(exp == Serializable.yes); } This is nice. Also it's base for library functions like hasNotes or getNotes!(Symbol, MyAttribute). This simple extension to the language enables libraries, using existing traits to navigate symbols, to get additional information about things and implement it however. The lack of user defined attributes is D's biggest missed opportunity right now, and I think this simple proposal will plug that hole. Yes, it's big drawback for serialization and data binding code. Previous user-defined attribute proposals have had counter arguments like these: 1) how do you define what is and is not a valid attribute? Here, the answer is pretty simple: you can put whatever notes you want on the thing. Whether the library uses it or not is up to it. It has to be a valid type - so the compiler will catch typos and whatnot - but it doesn't have to be used unless you ask for it. It should be any user-defined type that may be used at compile-time. For example @UUID("...") should be available out of the box. 2) OK, how do you namespace things so different libraries don't get different results? That's where the beauty of the expression type comes in: D already has namespaces. foo.Serializable != bar.Serializable, so there's no conflict. We simply declare types. The enum X {yes, no} pattern is already common in Phobos, and is also the best way to express a bool condition here. (Technically, @note(true) would compile, but it'd be much less useful than declaring a name for the note too, with an enum.) Name conflicts is a problem already solved by the language. Yes, it should be possible to write @std.UUID(""). 3) Can we have shared attributes, with declared names so people know what to use in their own libraries? Of course, for example consider a validating attribute "Flags": @Flags enum SomeFlags { a = 1, b = 2, c = 4, d = 8 } During attachment it would check if enum member's bits don't overlap.
Re: Proposal: user defined attributes
On 3/16/12 8:35 AM, Adam D. Ruppe wrote: enum Serializable { yes, no } @note(Serializable.yes) int a; [...] foreach(i, exp; __traits(getNotes, a)) { static assert(is(typeof(exp) == Serializable); static assert(exp == Serializable.yes); } So we have: class A { @note(Serializable.yes) int a; ... } vs. a hypothetical in-language solution: class A { int a; mixin(note("a", Serializable.yes)); ... } I wonder to what extent the in-language solution can be made to work. Andrei
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 16:09:55 UTC, Andrei Alexandrescu wrote: I wonder to what extent the in-language solution can be made to work. It can sort of work, but it isn't very good. (I thought you might say this too; check out this post: http://forum.dlang.org/thread/bccwycoexxykfgxve...@forum.dlang.org#post-gmtawdmaihzgxnvezfrf:40forum.dlang.org ) In that other post, I talked about function parameters (which is what I really want it for). The in-language solution for that can only be made to work with a pile of fragile hacks. But, even for functions, you just wrote: int a; mixin(note("a", Serializable.yes)); OK, that works... but what about: int a() { return 0; } mixin(note("a", Serializable.yes)); We're good so far... until: int a() { return 0; } int a(int b) { return 0; } mixin(note("a", Serializable.yes)); // which a? You could potentially solve that by using the mangle of instead of the string, and doing an alias template rather than passing a string directly, but I'm not sure if we actually can in today's dmd (I don't even know how to refer to the proper overload...) Also, what if the declaration is anonymous? You could still see it in reflection - a ParameterTypeTuple doesn't care about names - but you couldn't annotate it this way. I guess a workaround there would be giving it a name like _param_0. Moreover, the mixin adds some junk to the struct. If you iterate over allMembers, will you see enum _note_a_serializable; in there? If there's a consistent naming convention, we could skip it (my web.d ignores everything with a leading underscore, for example), but it is nevertheless letting implementation details slip out in reflection. Seeing how the whole point of this is to be used in reflection, that's a case I think is likely to cause annoyance in practice. The current language solution isn't really *bad* with enough library help, but it isn't particularly *good* either and I don't think it can be. I've tried a few things, and I still see the lack of user annotations as D's biggest miss right now.
Re: Proposal: user defined attributes
On Fri, 16 Mar 2012 09:35:54 -0400, Adam D. Ruppe wrote: On the ride over here today, I had a thought that I think neatly solves the user defined attribute question. enum Serializable { yes, no } @note(Serializable.yes) int a; I thought @ was supposed to be a user-defined annotation. Otherwise, why did we introduce @syntax? I'd rather see something like this: @annotation serializable(bool x = true) {return x ? Serializable.yes : Serializable.no;} // implicit auto @serializable int a; @serializable(false) int b; Where annotations have to be CTFE-able (because they are constructed at compile-time) -Steve
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 16:57:26 UTC, Steven Schveighoffer wrote: I thought @ was supposed to be a user-defined annotation. Otherwise, why did we introduce @syntax? idk, to "reduce" the number of keywords or somethiny. This is why I call it a mistake or missed opportunity right now though: @property, @safe, @disable, @system, and @trusted have already made a claim on the @syntax. Now, we have to work around that, which is why I'm thinking @note(expression) rather than @. I'd rather see something like this: I could live with that too, but I think it'd be harder to make happen due to potential clashes with the current thing @ is used for.
Re: Proposal: user defined attributes
On Fri, 16 Mar 2012 13:36:42 -0400, Adam D. Ruppe wrote: On Friday, 16 March 2012 at 16:57:26 UTC, Steven Schveighoffer wrote: I thought @ was supposed to be a user-defined annotation. Otherwise, why did we introduce @syntax? idk, to "reduce" the number of keywords or somethiny. Quote from TDPL (section 5.9.1 on page 156): "Attributes, always introduced with @, are simple adornments specifying certain features for the symbol being defined. Some attributes are recognized by the compiler; some are defined and used by the programmer alone." I assumed this was true, and thought so even before TDPL came out. See http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP6 This is why I call it a mistake or missed opportunity right now though: @property, @safe, @disable, @system, and @trusted have already made a claim on the @syntax. I think those are just compiler-defined attributes. They aren't keywords in the sense that the parser doesn't treat them as special. They are just another type of symbol. I could live with that too, but I think it'd be harder to make happen due to potential clashes with the current thing @ is used for. meh, just don't use @safe, @property, @disable, @system, and @trusted. I don't see a huge number of compiler-defined attributes springing up. Nor do I see a huge number of library or user-defined ones springing up. -Steve
Re: Proposal: user defined attributes
On 3/16/12, Adam D. Ruppe wrote: > The current language solution isn't really *bad* with enough > library help, but it isn't particularly *good* either and I > don't think it can be. I've tried a few things, and I still > see the lack of user annotations as D's biggest miss right now. Yeah, but I would say if we had even better compile-time introspection we could have the freedom to implement any number of annotation implementations in library code. When you put something into the language you have to depend on C++ hackers to implement and then inevitably fix the upcoming bugs in the front-end (ICEs are an annoying blocker), and there's always that issue where the devs are against adding new features to an existing language feature. (say annotations were implemented, soon enough someone is going to complain it doesn't have enough functionality and that it needs to be extended). Personally I'd love it if we had more __traits and compile-time introspection abilities.
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 18:07:18 UTC, Steven Schveighoffer wrote: Quote from TDPL (section 5.9.1 on page 156): Huh. There's nothing I can see in the compiler that even hints at this. The @ thing is just another storage class as far as it's concerned right now. Nor do I see a huge number of library or user-defined ones springing up. Yeah. I still really like my expression idea though, but thinking about your strategy, we could say: When you see @, if it is a compiler word after it, parse it that way. Otherwise, try to get a function call out of it. Treat the function call as an enum and add it to the list. Thus, it is CTFE, namespaced, etc. like normal. The return value is appended to the declaration's attribute expression list (so the end result is the same as I was thinking.) I'm pretty sure that'd work..
Re: Proposal: user defined attributes
On Fri, 16 Mar 2012 14:33:37 -0400, Adam D. Ruppe wrote: On Friday, 16 March 2012 at 18:07:18 UTC, Steven Schveighoffer wrote: Quote from TDPL (section 5.9.1 on page 156): Huh. There's nothing I can see in the compiler that even hints at this. The @ thing is just another storage class as far as it's concerned right now. Right, the user-defined portion is not implemented. Nor do I see a huge number of library or user-defined ones springing up. Yeah. I still really like my expression idea though, but thinking about your strategy, we could say: When you see @, if it is a compiler word after it, parse it that way. Otherwise, try to get a function call out of it. The way I'd like to see it work (and not being a compiler writer, I have no idea if/how this would work) is: When you see @, call a CTFE function with that name. The compiler defines intrinsic functions @property, @disable, etc. which return intrinsic data types that get appended to the attribute list. Then the compiler recognizes those data types in the attribute list when deciding how things should be compiled. This might not be feasible given the current implementation, or how compilers are designed, I have no idea. The return value is appended to the declaration's attribute expression list (so the end result is the same as I was thinking.) Yes. And I'd like to see the other intrinsic attributes appended (and queryable) as well. What we also may need in the @annotation declaration is an alias of the thing being compiled (again, don't know how feasible this is) for example: @annotation property(alias sym)() { static assert(is(sym == function)); return INTRINSIC.isProperty;} Maybe that's going too far :) -Steve
Re: Proposal: user defined attributes
Am Fri, 16 Mar 2012 16:21:41 +0100 schrieb Piotr Szturmaj : > > @note(Serializable.yes) int a; > > This is just enum. If you use struct or class attributes (like in C#) > then direct @Struct(constructor args..) might be better. > > +1 > > The expression inside is appended to a list on > > the declaration. > > > > This would be valid on variables, functions, > > function parameters, struct members, etc. > > > > 2) __traits(getNotes, decl). This returns a tuple > > of all the note expressions. > > > > foreach(i, exp; __traits(getNotes, a)) { > > static assert(is(typeof(exp) == Serializable); > > static assert(exp == Serializable.yes); > > } > > This is nice. Also it's base for library functions like hasNotes or > getNotes!(Symbol, MyAttribute). +1 > > 1) how do you define what is and is not a valid attribute? > > > > It should be any user-defined type that may be used at compile-time. > For example @UUID("...") should be available out of the box. Or we could add a @attribute attribute: @attribute struct Test { this(int a) {}... } @Test(99) string someTestVal; > > 2) OK, how do you namespace things so different libraries don't > > get different results? > > > > That's where the beauty of the expression type comes in: D > > already has namespaces. foo.Serializable != bar.Serializable, > > so there's no conflict. > > > > We simply declare types. The enum X {yes, no} pattern is already > > common in Phobos, and is also the best way to express a bool > > condition here. (Technically, @note(true) would compile, but it'd > > be much less useful than declaring a name for the note too, with an > > enum.) > > > > Name conflicts is a problem already solved by the language. > > Yes, it should be possible to write @std.UUID(""). > And all normal import rules should work for user defined attributes as well (renamed imports, static imports, ...).
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 16:09:55 UTC, Andrei Alexandrescu wrote: So we have: class A { @note(Serializable.yes) int a; ... } vs. a hypothetical in-language solution: class A { int a; mixin(note("a", Serializable.yes)); ... } I wonder to what extent the in-language solution can be made to work. Andrei This gets to an unreasonable amount of noise and complexity. First, you have the issue of using mixins. Using mixins is quite ugly. It's very tool unfriendly. It's not easily readable. It can mess up line numbers. It may or may not be limited in situations such as with parameters. In language solutions should be preferred for many things, but ultimately, not everything is a nail to hammer. Ultimately, I'd like to see being able to use any CTFE capable struct/class for an attribute with a constructor, ideally with access to the symbol it's defined on. This allows things like (if my unchecked code was correct): @attribute struct WebForm { string FormName; this(string FormName) { this.FormName = FormName; static assert(is(typeof(Symbol) : struct)); static assert(__traits(getAllMembers, Symbol).length > 0); // TODO: Make sure at least one member set to Browsable(true). } } @attribute struct Validate { string Pattern; this(string Pattern) { this.Pattern = Pattern; static assert(isValidRegex(Pattern)); } } @WebForm("Account"); @PostTo("Services/CreateAccount") @SecureOnly(true) struct CreateAccountForm { @Description("The name of your account. Must be between 3 and 12 letters."); @Validate(r"\w{3,12}") string Username; @Validate(r"\w+@\w+.\w+"); @Description("The email address to associate with this account."); string Email; } While it's a bit of boiler plate to create the library and attributes, you only need to do it once. Then you can make a very nice form that automatically validates fields both clientside (where JS and/or CSS3 is supported) and serverside (when posted to Services/CreateAccount). You can verify a bunch of things at compile-time, including that the service exists or that the validation contains valid regex. And best of all, it's actually readable unlike if you went with a mixin approach. You would end up having 7 random mixins in that above form, and have to manually check each one to see if it's creating code or just creating an attribute. This way, you can see the @ and know it's an attribute immediately. Another thing that doesn't come up yet but may in the future: reflection. It seems worrying to have random mixins adding reflection info, as that's a job for the compiler. It knows about when reflection is enabled, it knows how much it needs to generate, if things exist after optimization, etc. There's no point leaving that to a mixin and having to keep it in sync with the compiler. This way though, there's no need. The reflection data would just have an annotations property that can be accessed.
Re: Proposal: user defined attributes
On 3/17/12, Kapps wrote: > @WebForm("Account"); > @PostTo("Services/CreateAccount") > @SecureOnly(true) > struct CreateAccountForm { That kind of turns D from a structural to a declarative language. :p
Re: Proposal: user defined attributes
On Saturday, 17 March 2012 at 00:54:02 UTC, Andrej Mitrovic wrote: On 3/17/12, Kapps wrote: @WebForm("Account"); @PostTo("Services/CreateAccount") @SecureOnly(true) struct CreateAccountForm { That kind of turns D from a structural to a declarative language. :p Web design is quite a declarative thing. :) The code is already written for you, why bother writing it again instead of just writing it once and passing along essentially parameters to it. Anywho, something like that is a somewhat extreme case. Basic things include @serializable or @notserialized (or @serialized(false)). With the topic of dynamic/scripting languages, other things can include @scripted to indicate a method or class can be accessed from the script, or @scripted(Security.low) to indicate user scripts can access it and not just game scripts. This prevents having to make annoying bindings and communicate what's passed in to the script compiler. Instead, you can find out everything that can be passed in at compile-time, and upon script compilation you can verify the script has access to all of these methods, then statically call them without any of the performance hit you would normally have by using scripting, yet with the safety.
Re: Proposal: user defined attributes
El 16/03/2012 14:35, Adam D. Ruppe escribió: We introduce two new things to the language: 1) the @note(expression) attribute. You can put as many "notes" on a declaration as you want by simply listing them. I like that. I learned about annotations a couple years ago in two contexts: - Web Services in Java and C# - Hibernate in Java They come very handy and are hard to beat with current language features. [WebService] public class Service : WebService { [WebMethod] public string helloWorld() { return "Hello World"; } } What coult be a similar D with annotations?: @note(WebService) class Service : WebService { @note(WebMethod) string helloWorld() { return "Hello World"; } } and have some CTFE stuff generate the magic?
Re: Proposal: user defined attributes
On 17 March 2012 02:53, Andrej Mitrovic wrote: > On 3/17/12, Kapps wrote: > > @WebForm("Account"); > > @PostTo("Services/CreateAccount") > > @SecureOnly(true) > > struct CreateAccountForm { > > That kind of turns D from a structural to a declarative language. :p > And that's awesome in many situations! :) This also maps really well to games/tools/editors/script bindings. C# has this, and it's an invaluable language feature. It adds so much simplicity to the tools code.
Re: Proposal: user defined attributes
What we're talking about here is subject-oriented programming: having the attributes get enclosed into objects, rather then objects enclosing attributes. And this is extremely useful, IMO. On Sat, Mar 17, 2012 at 1:23 PM, Manu wrote: > On 17 March 2012 02:53, Andrej Mitrovic wrote: >> >> On 3/17/12, Kapps wrote: >> > @WebForm("Account"); >> > @PostTo("Services/CreateAccount") >> > @SecureOnly(true) >> > struct CreateAccountForm { >> >> That kind of turns D from a structural to a declarative language. :p > > > And that's awesome in many situations! :) > > This also maps really well to games/tools/editors/script bindings. C# has > this, and it's an invaluable language feature. It adds so much simplicity to > the tools code. -- Bye, Gor Gyolchanyan.
Re: Proposal: user defined attributes
On 2012-03-16 14:35, Adam D. Ruppe wrote: On the ride over here today, I had a thought that I think neatly solves the user defined attribute question. I would love to have user defined attributes in D but I'm not completely like your approach. I would go with something more like Java annotations. This is how I would like user defined attributes to work. Attributes can be applied to most declarations like: classes, fields, variables, functions, parameters and so on. Attributes are used with the following syntax: @foo(key = "value", key2 = "value2) class Bar {} "foo" is the name of the attribute. In the parentheses is a key-value list passed to the attribute. The values can be of any type available at compile time. Attributes are defined as follows: We add a new attribute called "@annotation" or "@attribute". This attribute is applied to a class or struct to make it an attribute: @attribute class foo { string key; string key2; } The keys the attribute accepts are declared in the class as either fields or methods (haven't decided yet). It's perfectly fine to have an attribute accepting no values which doesn't have to declare any keys: @attribute class bar {} If an attribute only accepts one value the name of the value needs to be "value": @attribute class fooBar { string value; } This allows to not have to specify the key when passing a value to the attribute: @fooBar("asd") class Foo {} Accessing information about attribute should be possible both during compile time and runtime. At compile time "__traits" can be used: __traits(hasAttribute, bar, Foo); // returns true if the attribute "bar" as been applied to "Foo" __traits(getAttribute, bar, key, Foo); // returns the value of the key "key" This is all very similar to how it works in Java: http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 3/16/2012 7:11 AM, Manu wrote: attribute myAttribute { this(int something); bool bNeedsAttention; property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } } @myAttribute(10) int thing; thing.refresh = true; Under the hood, where would that per-instance data be stored? Compile-time annotations can be stored internally to the compiler, but per-instance runtime data? How is it connected to the instance? When is it constructed and destroyed?
Re: Proposal: user defined attributes
On 17 March 2012 21:56, Walter Bright wrote: > On 3/16/2012 7:11 AM, Manu wrote: > >> attribute myAttribute >> { >> this(int something); >> >> bool bNeedsAttention; >> >> property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } >> } >> >> @myAttribute(10) int thing; >> >> thing.refresh = true; >> > > Under the hood, where would that per-instance data be stored? > > Compile-time annotations can be stored internally to the compiler, but > per-instance runtime data? How is it connected to the instance? When is it > constructed and destroyed? > In Java+C# it just lives in the class somewhere. Put it right beside the attributed member, or maybe separate them into an attribute section at the end of the class (to preserve structural layout). Construct along with the class, I suppose the moment would be after member initialisation, but before the constructor executes. I wonder if it should only be allowed on classes/class members... adding hidden data to a 'struct' almost defeats the purpose. Java doesn't have 'struct', so no problem. I wonder what C# does exactly...
Re: Proposal: user defined attributes
On 17 March 2012 23:52, Manu wrote: > On 17 March 2012 21:56, Walter Bright wrote: > >> On 3/16/2012 7:11 AM, Manu wrote: >> >>> attribute myAttribute >>> { >>> this(int something); >>> >>> bool bNeedsAttention; >>> >>> property void refresh(bool bRefresh) { bNeedsAttention = bRefresh; } >>> } >>> >>> @myAttribute(10) int thing; >>> >>> thing.refresh = true; >>> >> >> Under the hood, where would that per-instance data be stored? >> >> Compile-time annotations can be stored internally to the compiler, but >> per-instance runtime data? How is it connected to the instance? When is it >> constructed and destroyed? >> > > In Java+C# it just lives in the class somewhere. Put it right beside the > attributed member, or maybe separate them into an attribute section at the > end of the class (to preserve structural layout). Construct along with the > class, I suppose the moment would be after member initialisation, but > before the constructor executes. > I wonder if it should only be allowed on classes/class members... adding > hidden data to a 'struct' almost defeats the purpose. Java doesn't have > 'struct', so no problem. I wonder what C# does exactly... > I tend to think of 'struct's as 'passive', and compile-time annotations would provide me with every use case I can imagine for my own purposes in the case of structs. classes seem far more likely to need stateful attributes.
Re: Proposal: user defined attributes
On 3/17/2012 2:55 PM, Manu wrote: I tend to think of 'struct's as 'passive', and compile-time annotations would provide me with every use case I can imagine for my own purposes in the case of structs. classes seem far more likely to need stateful attributes. I currently find the notion of runtime attribute state to be fraught with all kinds of unresolved and murky issues with no obvious answer: 1. construction/destruction 2. shared 3. const/immutable 4. thread locality 5. allocated statically or dynamically 6. shared library issues? If the attribute is code, when does that code get run? 1. on initialization 2. on termination 3. on read 4. on write 5. what about read/write?
Re: Proposal: user defined attributes
On 18 March 2012 03:10, Walter Bright wrote: > On 3/17/2012 2:55 PM, Manu wrote: > >> I tend to think of 'struct's as 'passive', and compile-time annotations >> would >> provide me with every use case I can imagine for my own purposes in the >> case of >> structs. classes seem far more likely to need stateful attributes. >> > > I currently find the notion of runtime attribute state to be fraught with > all kinds of unresolved and murky issues with no obvious answer: > > 1. construction/destruction > After initialisation, before construction. 2. shared > How is this any different than for the class its self? 3. const/immutable > Inherit these properties. 4. thread locality > Same as class. 5. allocated statically or dynamically > I'd say dynamically if restricted to classes, but some suggested the syntax '@attribute struct/class MyAttribute { }', which could clarify the intent. 6. shared library issues? > If extern(D), then there should be no problems. If extern(C), then the attributes would just appear like structure members. Assuming the layout was documented (ie, in-order of appearance, at the end of the class), C/C++ could include them at the end of the class definition, and access them directly as if usual classes. All that would be lost is the implicit (compile time) association between the attribute and its associated class member. I don't think it's fair to expect a novel language feature to be supported by C/C++ though. If the attribute is code, when does that code get run? > > 1. on initialization > 2. on termination > 3. on read > 4. on write > 5. what about read/write? > I might go and read up on C# more thoroughly and get back to you... maybe others here are already more familiar with C#'s attribute management? I'm sure C# already answers all these questions. It has precisely the same set of issues associated.
Re: Proposal: user defined attributes
On 3/17/2012 6:39 PM, Manu wrote: I'm sure C# already answers all these questions. It has precisely the same set of issues associated. C# doesn't have RAII, immutable, nor the notion of threadlocal/shared types.
Re: Proposal: user defined attributes
On 18 March 2012 03:48, Walter Bright wrote: > On 3/17/2012 6:39 PM, Manu wrote: > >> I'm sure C# already answers all these questions. It has precisely the >> same set >> of issues associated. >> > > C# doesn't have RAII, immutable, nor the notion of threadlocal/shared > types. > C# has immutable. How does RAII cause a problem here? The threadlocal/shared stuff shouldn't be a problem, since the attribute instances are contained by the class its self, it just has the same locality properties. Can you imagine a case where that would be problematic?
Re: Proposal: user defined attributes
On 3/17/2012 7:04 PM, Manu wrote: On 18 March 2012 03:48, Walter Bright mailto:newshou...@digitalmars.com>> wrote: On 3/17/2012 6:39 PM, Manu wrote: I'm sure C# already answers all these questions. It has precisely the same set of issues associated. C# doesn't have RAII, immutable, nor the notion of threadlocal/shared types. C# has immutable. No, it does not. How does RAII cause a problem here? Generally, supporting it tends to permeate the semantics of the language. Simple things like copying a value onto the parameter stack entail all kinds of issues. The threadlocal/shared stuff shouldn't be a problem, since the attribute instances are contained by the class its self, it just has the same locality properties. Can you imagine a case where that would be problematic? If it's shared, how is access to the data controlled if multiple threads access it at the same time?
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 01:48:07 UTC, Walter Bright wrote: On 3/17/2012 6:39 PM, Manu wrote: I'm sure C# already answers all these questions. It has precisely the same set of issues associated. C# doesn't have RAII, immutable, nor the notion of threadlocal/shared types. It has threadlocal using the [ThreadLocal] attribute which gets implemented by the compiler. In C#, all attributes live inside the TypeInfo/MethodInfo/etc for the class/struct/method/field/parameter. I don't see this being a problem. I can't think of good use cases where an attribute/annotation should be per-instance at all, particularly with the compile-time power that D has, whereas C# does not have any. Honestly, most uses of attributes in D would be done at compile-time, and I think that's acceptable until/if runtime reflection is put in. If it is needed, it can live inside TypeInfo/MethodInfo, but is (imo) absolutely not needed on a per-instance basis. This is the job of fields or interfaces.
Re: Proposal: user defined attributes
On 3/17/2012 8:04 PM, Kapps wrote: It has threadlocal using the [ThreadLocal] attribute which gets implemented by the compiler. That's a storage class, not a type constructor. In D, threadlocal/shared is a difference in the type. In C#, all attributes live inside the TypeInfo/MethodInfo/etc for the class/struct/method/field/parameter. I don't see this being a problem. I can't think of good use cases where an attribute/annotation should be per-instance at all, particularly with the compile-time power that D has, whereas C# does not have any. Honestly, most uses of attributes in D would be done at compile-time, and I think that's acceptable until/if runtime reflection is put in. If it is needed, it can live inside TypeInfo/MethodInfo, but is (imo) absolutely not needed on a per-instance basis. This is the job of fields or interfaces. I also do not get why per-instance attributes even exist, as I agree that's what fields are for.
Re: Proposal: user defined attributes
Walter, how do you feel about the compile time annotation list? I looked at implementing it, and it is a little more involved than I thought (mainly in changing parse.c to treat @ things as more than just storage classes), but still not terrible.
Re: Proposal: user defined attributes
Walter Bright wrote: I also do not get why per-instance attributes even exist, as I agree that's what fields are for. Attributes are per-type (type properties, methods, etc), not per-instance, and only accessible (in C#) through type reflection (to my knowledge). According to http://msdn.microsoft.com/en-us/library/z919e8tw(v=vs.80).aspx attribute objects aren't constructed until reflected upon. I think attributes in combination with D's templates would be very useful: @attribute class Cool { bool isCool; this(bool cool) { isCool = cool; } } class CoolClass(bool cool) { @CoolType(cool); int type; } void main() { auto cc = new CoolClass!true(); if (cc.type@Cool.isCool) { // (new Cool(true)).isCool // Do something cool... } } Or, if @attributes could be applied to *any* type (enums, structs, variables, etc..), we could write this more simply: @attribute bool isCool; class CoolClass(bool cool) { @isCool = cool; int type; } void main() { auto cc = new CoolClass!true(); if (cc.type@isCool) { // true // Do something cool... } } and of course, the compiler could make use of attribute metadata during codegen. Things like Garbage Collection and memory compaction attributes come to mind: class MemoryPool { @GC.DontScan void*[] pool; @Int.Fast int index; // replace stdint } Also, aliasing could be possible: @Int.Fast alias int intf; @Int.Least alias int intl;
Re: Proposal: user defined attributes
F i L wrote: class CoolClass(bool cool) { @CoolType(cool); int type; } typo **@Cool(cool); plus, I think a better syntax for attributes might be to have an attribute keyword for definitions and only use "@" for application: attribute struct CoolType { ... } attribute bool isCool; @CoolType @(isCool = true) string coolText;
Re: Proposal: user defined attributes
On 3/17/2012 9:12 PM, F i L wrote: Walter Bright wrote: I also do not get why per-instance attributes even exist, as I agree that's what fields are for. Attributes are per-type (type properties, methods, etc), not per-instance, and only accessible (in C#) through type reflection (to my knowledge). According to http://msdn.microsoft.com/en-us/library/z919e8tw(v=vs.80).aspx attribute objects aren't constructed until reflected upon. My impression is it is just obfuscation around a simple lazy initialization pattern. While I can see the abstraction usefulness of compile time attribute metadata, I am having a hard time seeing what the gain is with runtime attributes over more traditional techniques.
Re: Proposal: user defined attributes
Walter Bright wrote: My impression is it is just obfuscation around a simple lazy initialization pattern. While I can see the abstraction usefulness of compile time attribute metadata, I am having a hard time seeing what the gain is with runtime attributes over more traditional techniques. I'm not sure exactly what you mean by runtime attributes. Do you mean the ability to reflect upon attributes at runtime? In that case, there's two benefits I can think of over "traditional" member data: Instance memory (attributes are create at reflection), and reusable metadata packages (similar to how you might use mixin templates only with less noise and reflection capabilities).
Re: Proposal: user defined attributes
On 3/17/2012 10:01 PM, F i L wrote: Walter Bright wrote: My impression is it is just obfuscation around a simple lazy initialization pattern. While I can see the abstraction usefulness of compile time attribute metadata, I am having a hard time seeing what the gain is with runtime attributes over more traditional techniques. I'm not sure exactly what you mean by runtime attributes. Do you mean the ability to reflect upon attributes at runtime? I mean there is modifiable-at-runtime, instance-specific data. In that case, there's two benefits I can think of over "traditional" member data: Instance memory (attributes are create at reflection), Lazy initialization is a standard pattern. No special language features are needed for it. and reusable metadata packages (similar to how you might use mixin templates only with less noise and reflection capabilities). Sounds like a garden variety user-defined data type. Again, I am just not seeing the leap in power with this. It's a mystery to me how a user defined "attribute class" is different in any way from a user defined class, and what advantage special syntax gives a standard pattern for lazy initialization, and why extra attribute fields can't be just, well, fields.
Re: Proposal: user defined attributes
On 3/17/2012 8:12 PM, Adam D. Ruppe wrote: Walter, how do you feel about the compile time annotation list? I feel it has merit, but I think it is possibly more complex than necessary. Note that I have never used user defined attributes, so I don't have experience to guide me on this.
Re: Proposal: user defined attributes
Walter Bright wrote: I mean there is modifiable-at-runtime, instance-specific data. In C#, no there isn't. Attributes are simply objects constructed (when gotten) from an Entity's metadata. No memory is stored per-instance unless you manage the objects manually: class A : Attribute { public string s = "Default"; } [TestA] class C {} static void Main() { // The line below is equivalent to: var a = new A(); // except that it's construction is defined by // metadata stored in type C. var a = typeof(C).GetCustomAttributes(true)[0] as A; a.s = "Modification"; Console.WriteLine(a.s); // prints "Modification" // Therefor... var b = typeof(C).GetCustomAttributes(true)[0] as A; Console.WriteLine(b.s); // prints "Default" } In that case, there's two benefits I can think of over "traditional" member data: Instance memory (attributes are create at reflection), Lazy initialization is a standard pattern. No special language features are needed for it. I see how my statements (and code examples) where confusing. I meant that no attribute data is stored per-instance at all (unless traditionally done so), and that attribute objects are simply create in-place at the point of access. So to clarify my previous code a bit: attribute class A { string i = "Default"; } @A class C { A a; } void main() { auto a = C@A; // create new A based on C assert(is(typeof(a) : A)); // alternatively you could do: auto c = new C(); auto a = c@A; // same as: typeof(c)@A c.a = c@A; // explicitly store attribute } Note: Might want to use the "new" keyword with class type attributes (auto a = new C@A), but the idea's there. Plus, I think that looks a lot better than the C# version. and reusable metadata packages (similar to how you might use mixin templates only with less noise and reflection capabilities). Sounds like a garden variety user-defined data type. It is. Only it's a data type who's construction values are stored in metadata (per entity), and therefor can be used at both compile and run times. By per-entity I mean for each unique Type, Type member, Sub-Type, etc. I don't know of any existing D idiom that is capable of what I presented. If there is, I would like to know. Here's the closest I can think of: mixin template CoolInt(bool cool, string name) { mixin("enum bool " ~ name ~ "_isCool = cool;"); mixin("int " ~ name ~ ";"); } class CoolClass { mixin CoolInt!(true, "a"); mixin CoolInt!(false, "b"); } void main() { auto c = new CoolClass(); writeln(c.a_isCool); // true writeln(c.b_isCool); // false } which, aside from noise, is great for runtime reflection, but it's completely useless (i think) for the compiler because the variables are created through arbitrary strings. Plus, I don't know how you'd store anything but simple variables, which more complex data would require a lot of _variables.
Re: Proposal: user defined attributes
F i L wrote: Plus, I don't know how you'd store anything but simple variables, which more complex data would require a lot of _variables. I found a way: mixin template Attribute( string type, string name, string attr, Params...) { mixin (type ~ " " ~ name ~ ";"); mixin ( "auto " ~ name ~ "_" ~ attr ~ "()" ~ "{ return new " ~ attr ~ "(Params); }" ); } class Cool { string s; this(string s) { this.s = s; } } class CoolClass { mixin Attribute!("int", "a", "Cool", "Heh"); mixin Attribute!("int", "b", "Cool", "Sup"); } void main() { auto c = new CoolClass(); writeln(c.a, ", ", c.b); // 0, 0 writeln(c.a_Cool().s); // Heh writeln(c.b_Cool().s); // Sup }
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 10:25:20 UTC, F i L wrote: F i L wrote: class CoolClass { mixin Attribute!("int", "a", "Cool", "Heh"); mixin Attribute!("int", "b", "Cool", "Sup"); } void main() { auto c = new CoolClass(); writeln(c.a, ", ", c.b); // 0, 0 writeln(c.a_Cool().s); // Heh writeln(c.b_Cool().s); // Sup } Is it not possible to alias a mixin to just one letter, and then use it to have any syntax we want... something like this: x("@attribute(Serializable.yes) int a");
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 10:38:19 UTC, Tove wrote: On Sunday, 18 March 2012 at 10:25:20 UTC, F i L wrote: F i L wrote: class CoolClass { mixin Attribute!("int", "a", "Cool", "Heh"); mixin Attribute!("int", "b", "Cool", "Sup"); } void main() { auto c = new CoolClass(); writeln(c.a, ", ", c.b); // 0, 0 writeln(c.a_Cool().s); // Heh writeln(c.b_Cool().s); // Sup } Is it not possible to alias a mixin to just one letter, and then use it to have any syntax we want... something like this: x("@attribute(Serializable.yes) int a"); Sure, but there's still the issue of using attributes for codegen. For instance compare: struct Test { @GC.NoScan int value; } to, the current: struct Test { int value; this() { GC.setAttr(&value, NO_SCAN); } } How can we do that with mixin templates? If attributes where a language type the compiler could exploit in a consistent way, It would be *trivial* describing this behavior in a declarative way.
Re: Proposal: user defined attributes
F i L wrote: struct Test { int value; this() { GC.setAttr(&value, NO_SCAN); } } bleh, should be... struct Test { int value; this(int v) { GC.setAttr(&value, GC.BlkAttr.NO_SCAN); } } Or something like that. I've never actually set GC attributes before. But this also raises another issue. Structs don't have default constructors, so applying NoScan attributes (by default) is, to my knowledge, impossible. Whereas it could (?) be possible through attributes.
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 10:50:14 UTC, F i L wrote: x("@attribute(Serializable.yes) int a"); Sure, but there's still the issue of using attributes for codegen. For instance compare: struct Test { @GC.NoScan int value; } to, the current: struct Test { int value; this() { GC.setAttr(&value, NO_SCAN); } } How can we do that with mixin templates? If attributes where a language type the compiler could exploit in a consistent way, It would be *trivial* describing this behavior in a declarative way. Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later... x!("@GC.NoScan int value;"); // modified by x to insert a foreach with GC.setAttr x!(q{this() {/* foreach(...) GC.setAttr(...); */ }); But I guess one lose the opportunity for some compile time magic... in a more efficient way than exposed by the GC.settAttr API.(just pure speculation, I don't have sufficient knowledge of the internal representation of our GC design.).
Re: Proposal: user defined attributes
On 18 March 2012 05:04, Kapps wrote: > On Sunday, 18 March 2012 at 01:48:07 UTC, Walter Bright wrote: > >> On 3/17/2012 6:39 PM, Manu wrote: >> >>> I'm sure C# already answers all these questions. It has precisely the >>> same set >>> of issues associated. >>> >> >> C# doesn't have RAII, immutable, nor the notion of threadlocal/shared >> types. >> > > It has threadlocal using the [ThreadLocal] attribute which gets > implemented by the compiler. > > In C#, all attributes live inside the TypeInfo/MethodInfo/etc for the > class/struct/method/field/**parameter. I don't see this being a problem. > I can't think of good use cases where an attribute/annotation should be > per-instance at all, particularly with the compile-time power that D has, > whereas C# does not have any. Honestly, most uses of attributes in D would > be done at compile-time, and I think that's acceptable until/if runtime > reflection is put in. If it is needed, it can live inside > TypeInfo/MethodInfo, but is (imo) absolutely not needed on a per-instance > basis. This is the job of fields or interfaces. > I think that's a fair call. I wonder why Java feels the need for stateful attributes. I have made extensive use of java attributes that have been stateful. Java's persistence api's rely on stateful attributes a lot, but I think that can be done in other ways in D. Compile-time attributes sound like a great start, it's much simpler. But they do need to be able to 'do stuff', ie, add some property/method to a field (using the field its self as the context pointer), not just simply 'tag' it.
Re: Proposal: user defined attributes
Tove wrote: Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later... x!("@GC.NoScan int value;"); // modified by x to insert a foreach with GC.setAttr x!(q{this() {/* foreach(...) GC.setAttr(...); */ }); But if x!() pumps out a constructor, how do you add multiple attributes with @GC.NoScan? The constructors would collide.
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 12:10:23 UTC, F i L wrote: Tove wrote: Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later... x!("@GC.NoScan int value;"); // modified by x to insert a foreach with GC.setAttr x!(q{this() {/* foreach(...) GC.setAttr(...); */ }); But if x!() pumps out a constructor, how do you add multiple attributes with @GC.NoScan? The constructors would collide. 1. x! would parse all decls at compile time... 2. all attributes that need to modify the constructor is inserted at the points where the x! enabled constructors are declared/implemented... x!("@GC.NoScan @GC.Hot @attribute(Serializable.yes) int value;"); x!(q{this() { /* everything from 'x' is auto inserted here */ my; normal; constructor; tokens; });
Re: Proposal: user defined attributes
Tove wrote: 1. x! would parse all decls at compile time... 2. all attributes that need to modify the constructor is inserted at the points where the x! enabled constructors are declared/implemented... x!("@GC.NoScan @GC.Hot @attribute(Serializable.yes) int value;"); x!(q{this() { /* everything from 'x' is auto inserted here */ my; normal; constructor; tokens; }); I see, that would work. But why not just build this same operation into the compiler so the definition syntax is the same as usual. The mixin's are powerful but a bit ugly. Not to mention not IDE parser on the planet is going to be able to figure out all that to give you intelligent code-completion.
Re: Proposal: user defined attributes
On Sunday, 18 March 2012 at 12:39:19 UTC, F i L wrote: Tove wrote: 1. x! would parse all decls at compile time... 2. all attributes that need to modify the constructor is inserted at the points where the x! enabled constructors are declared/implemented... x!("@GC.NoScan @GC.Hot @attribute(Serializable.yes) int value;"); x!(q{this() { /* everything from 'x' is auto inserted here */ my; normal; constructor; tokens; }); I see, that would work. But why not just build this same operation into the compiler so the definition syntax is the same as usual. The mixin's are powerful but a bit ugly. Not to mention not IDE parser on the planet is going to be able to figure out all that to give you intelligent code-completion. Yes, I was thinking along these lines... what would be the absolutely bare minimum needed support this from the compiler to make this "scheme" look first class? what if... the compiler encounters an unknown @token then it would delegate the parsing to a library implementation... which basically would do the above, but it would be hidden from the user... this way we would get a 0 effort(from the perspective of the compiler) and extensible syntax in library covering all future needs.
Re: Proposal: user defined attributes
On 3/18/2012 2:47 AM, F i L wrote: Walter Bright wrote: I mean there is modifiable-at-runtime, instance-specific data. In C#, no there isn't. Attributes are simply objects constructed (when gotten) from an Entity's metadata. No memory is stored per-instance unless you manage the objects manually: class A : Attribute { public string s = "Default"; } [TestA] class C {} static void Main() { // The line below is equivalent to: var a = new A(); // except that it's construction is defined by // metadata stored in type C. var a = typeof(C).GetCustomAttributes(true)[0] as A; a.s = "Modification"; Console.WriteLine(a.s); // prints "Modification" // Therefor... var b = typeof(C).GetCustomAttributes(true)[0] as A; Console.WriteLine(b.s); // prints "Default" } Which looks indistinguishable from modifiable at runtime, instance specific data. Lazy initialization is a standard pattern. No special language features are needed for it. I see how my statements (and code examples) where confusing. I meant that no attribute data is stored per-instance at all (unless traditionally done so), and that attribute objects are simply create in-place at the point of access. So to clarify my previous code a bit: attribute class A { string i = "Default"; } @A class C { A a; } void main() { auto a = C@A; // create new A based on C assert(is(typeof(a) : A)); // alternatively you could do: auto c = new C(); auto a = c@A; // same as: typeof(c)@A c.a = c@A; // explicitly store attribute } Note: Might want to use the "new" keyword with class type attributes (auto a = new C@A), but the idea's there. Plus, I think that looks a lot better than the C# version. Sorry, it still looks like standard lazy initialization. I don't know what attributes add to the party. Sounds like a garden variety user-defined data type. It is. Only it's a data type who's construction values are stored in metadata (per entity), and therefor can be used at both compile and run times. By per-entity I mean for each unique Type, Type member, Sub-Type, etc. I don't know of any existing D idiom that is capable of what I presented. Simply use a normal class. Instantiate it at runtime as needed. which, aside from noise, is great for runtime reflection, but it's completely useless (i think) for the compiler because the variables are created through arbitrary strings. Plus, I don't know how you'd store anything but simple variables, which more complex data would require a lot of _variables. Something like Jacob's proposal for compile time attributes would be useful here. My failure to understand is about runtime attributes.
Re: Proposal: user defined attributes
On 2012-03-18 20:26, Walter Bright wrote: Something like Jacob's proposal for compile time attributes would be useful here. My failure to understand is about runtime attributes. If we'll get user defined attributes that is accessible via runtime reflection I'm sure people will find uses cases for it that are not possible with compile time reflection. But currently I don't see any use cases for attributes per instance. If I'm thinking correctly this can be used for serializing. Say that you want to serialize an object through a base class reference. Currently you will need to register the subclass using some mechanism due to the limited runtime reflection in D. But if it would be possible to enumerate all fields in a class and also set and get the values of the fields using runtime reflection it wouldn't be necessary to register the subclass. Ok, now to the user defined attribute: @attribute class NonSerialized {} // This is what's called a "marker" in Java. It doesn't contain any information, the information is the type itself. @attribute class SerializeAs { string value; } class Base { int x; @SerializeAs(foo) int y; @NonSerialized int c; } @NonSerialized class Sub : Base { int z; } Base sub = new Sub; serialize(sub); In this example the user defined attribute "NonSerialized" indicates that the class shouldn't be serialized. When the serializer is serializing "sub" the compile time type will be "Base" therefore it would need to use runtime reflection to also serialize the fields added in the subclass "Sub". To check if the object should be serialized the serializer need to be able to access user defined attributes using runtime reflection. Something like: auto classInfo = sub.classinfo; writeln(classInfo); // Sub if (classInfo.hasAttribute("NonSerialized")) // skip serialization else { foreach (field ; classInfo.fields) if (!field.hasAttribute("NonSerialized")) { auto value = filed.value; string name; if (attribute = filed.attributes["SerializeAs"]) name = attribute.value; else name = filed.name; // serialize the field } } We do all this during runtime because we want to serialize through base class references. If the runtime type is the same as the compile time type we can do this at compile time. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 3/18/2012 2:58 PM, Jacob Carlborg wrote: Ok, now to the user defined attribute: @attribute class NonSerialized {} // This is what's called a "marker" in Java. It doesn't contain any information, the information is the type itself. @attribute class SerializeAs { string value; } class Base { int x; @SerializeAs(foo) int y; @NonSerialized int c; } @NonSerialized class Sub : Base { int z; } Base sub = new Sub; serialize(sub); In this example the user defined attribute "NonSerialized" indicates that the class shouldn't be serialized. When the serializer is serializing "sub" the compile time type will be "Base" therefore it would need to use runtime reflection to also serialize the fields added in the subclass "Sub". To check if the object should be serialized the serializer need to be able to access user defined attributes using runtime reflection. I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? How does any of this tell you how to serialize an int? How is Base.c also a NonSerialized with c in a superclass of it? ?? Maybe this is why I don't much care for attributes - it's all just a fog to me what is happening.
Re: Proposal: user defined attributes
On Friday, 16 March 2012 at 13:35:55 UTC, Adam D. Ruppe wrote: On the ride over here today, I had a thought that I think neatly solves the user defined attribute question. Maybe there are other ways to think about user defined attributes. I'd like them to essentially be ways to extend the static type system in library code. I am thinking about things like the ones done by Dehydra and Treehydra (https://developer.mozilla.org/en/Dehydra https://developer.mozilla.org/en/Treehydra ) but using the D language itself instead of JavaScript. This asks for more __traits(...), to allow the D programmer (that is defining a new attribute) to use them to static verify more characteristics of the D code being annotated with the attributes. Bye, bearophile
Re: Proposal: user defined attributes
Walter Bright wrote: I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? He's giving an example of serialize() below the code you quoted. Walter Bright wrote: Which looks indistinguishable from modifiable at runtime, instance specific data. If you're *only* considering the runtime ability of attributes, then it is. This: attribute struct A { this(int x, int y); void foo(); } @A(1, 2) struct C {} void main() { auto a = C@A; a.foo(); } would be conceptually equivalent to writing: struct A { this(int x, int y); void foo(); } struct C { static auto _A() { return A(1, 2); } } void main() { auto a = C._A(); a.foo(); } and it's my fault for not illustrating the important difference in the first place. Which is: Attributes are understandable by the compiler, therefor, attributes can describe behavior of an entity and inject code into key places where that entity is allocated/constructed/etc. For instance, C# does not directly support Unions, however creating the structure is possible, like so: [StructLayout(LayoutKind.Explicit)] struct MyUnion { [FieldOffset(0)] int a; [FieldOffset(0)] long b; [FieldOffset(0)] float c; } Because Attributes are defined with unique syntax, they can be stored uniquely by the compiler, and then reacted upon _in a variety of ways_. They are available at runtime so that runtime code can react to them as well. To illustrate what Trove and I have been talking about, If I wanted to "mark" a variable so that the GC wouldn't scan it, I might be able to write something like: attribute class Memory { GC.BlkAttr blkAttr; this(GC.BlkAttr attr) { blkAttr = attr; } @this(void* entity) { // the code in this function gets injected into // this() of the entity this class is attached to GC.setAttr(entity, blkAttr); } } The "@this(void*)" function might always take in a void* (much like how new() always takes uint/size_t) which points to the entity it's attributing. So if we then write: @Memory(GC.BlkAttr.NO_SCAN) string myString; Then when "myString.init()" is called, "GC.setAttr(myString, GC.BlkAttr.NO_SCAN)" will also be executed. I don't know enough about DMD's internals to know about how this would play out internally, but the concept is there. And I know my syntax has be changing over the last few posts (I've been going through different ideas), so I apologize if I'm being hard to follow here.
Re: Proposal: user defined attributes
Am 19.03.2012 01:41, schrieb Walter Bright: I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? How does any of this tell you how to serialize an int? How is Base.c also a NonSerialized with c in a superclass of it? attributes does not containing code - there just a (at-runtime) queryable information that can be attached to serveral things (like classes, methods, ...) - think of it like double.epsilon - but extendable by users - thats it, and in the c# world these attribute-definitions tend to be something like an class (but without code) in c# you can walk by (runtime)reflection through your code and find out if something is annotated with an special attribute and use the configure information and do something with it - call an constructor, open an connection, generated code (at runtime) - whatever you want its a easy-to-use-buildin-attribution-system thats it - and people like them because c# do all the big magic by giving developers a bunch of attributes that are then used for stuff like serialization, memory-layout, ... a compiletime example of this could be: attribute my_special_attribute { int version; } attribute my_special_attribute2 { string test; } class test { [my_special_attribute(version=2)] int method1(); [my_special_attribute(version=2)] [my_special_attribute2(test="bert")] int method2(); } void main() { auto b = [ __traits(allMembers, D) ]; foreach( auto a; b ) { -->attribute query magic -->auto c = [ __traits(attribute("my_special_attribute", a) ]; -->auto c = [ __traits(attribute("my_special_attribute2", a) ]; //now we know all methods with my_special_attribute //and speical_special_attribute2 and their content (version=2 //and test="bert" //now think of an template or mixing that uses this //information for code-generation or something like that //thats all } }
Re: Proposal: user defined attributes
Except for shared types, since in C# data is shared by default, everything else is available: RAII-> using () immutable -> achieved via cons/readonly (good enough for most purposes) ThreadLocal -> ThreadLocal class "Walter Bright" wrote in message news:jk3esn$1697$1...@digitalmars.com... On 3/17/2012 6:39 PM, Manu wrote: I'm sure C# already answers all these questions. It has precisely the same set of issues associated. C# doesn't have RAII, immutable, nor the notion of threadlocal/shared types.
Re: Proposal: user defined attributes
On Monday, 19 March 2012 at 06:46:09 UTC, dennis luehring wrote: Am 19.03.2012 01:41, schrieb Walter Bright: I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? How does any of this tell you how to serialize an int? How is Base.c also a NonSerialized with c in a superclass of it? attributes does not containing code - there just a (at-runtime) queryable information that can be attached to serveral things (like classes, methods, ...) - think of it like double.epsilon - but extendable by users - thats it, and in the c# world these attribute-definitions tend to be something like an class (but without code) in c# you can walk by (runtime)reflection through your code and find out if something is annotated with an special attribute and use the configure information and do something with it - call an constructor, open an connection, generated code (at runtime) - whatever you want its a easy-to-use-buildin-attribution-system thats it - and people like them because c# do all the big magic by giving developers a bunch of attributes that are then used for stuff like serialization, memory-layout, ... a compiletime example of this could be: attribute my_special_attribute { int version; } attribute my_special_attribute2 { string test; } class test { [my_special_attribute(version=2)] int method1(); [my_special_attribute(version=2)] [my_special_attribute2(test="bert")] int method2(); } void main() { auto b = [ __traits(allMembers, D) ]; foreach( auto a; b ) { -->attribute query magic -->auto c = [ __traits(attribute("my_special_attribute", a) ]; -->auto c = [ __traits(attribute("my_special_attribute2", a) ]; //now we know all methods with my_special_attribute //and speical_special_attribute2 and their content (version=2 //and test="bert" //now think of an template or mixing that uses this //information for code-generation or something like that //thats all } } Well I was thinking if we can go one step further than C#, because of D:s CTFE... by introducing a call back from the D compiler to the library CTFE attribute handler... this way we can hide all reflection from the "end user"... and the compiler doesn't need to know anything at all, as the library does the semantic lowering. @GC.NoScan int value; @GC this() {} Compiler Asks library for transformation of unknown @GC bool library("@GC this() {anything...}") -> if the library succeeds it would then transform the string and hand back a lowered mixin to the compiler. mixin(" this() { auto b = [ __traits(allMembers, D) ]; foreach( auto a; b) {DO.GC.Stuff...} anything... } ");
Re: Proposal: user defined attributes
i don't get the GC relation here? all attribute values are static const - because they are type-related (static) and read-only, attributes are type orientated not instance orientated @GC.NoScan int value; @GC this() {} Compiler Asks library for transformation of unknown @GC bool library("@GC this() {anything...}") -> if the library succeeds it would then transform the string and hand back a lowered mixin to the compiler. mixin(" this() { auto b = [ __traits(allMembers, D) ]; foreach( auto a; b) {DO.GC.Stuff...} anything... } ");
Re: Proposal: user defined attributes
On 2012-03-19 01:41, Walter Bright wrote: On 3/18/2012 2:58 PM, Jacob Carlborg wrote: Ok, now to the user defined attribute: @attribute class NonSerialized {} // This is what's called a "marker" in Java. It doesn't contain any information, the information is the type itself. @attribute class SerializeAs { string value; } class Base { int x; @SerializeAs(foo) int y; @NonSerialized int c; } @NonSerialized class Sub : Base { int z; } Base sub = new Sub; serialize(sub); In this example the user defined attribute "NonSerialized" indicates that the class shouldn't be serialized. When the serializer is serializing "sub" the compile time type will be "Base" therefore it would need to use runtime reflection to also serialize the fields added in the subclass "Sub". To check if the object should be serialized the serializer need to be able to access user defined attributes using runtime reflection. I'm sorry, I find this *massively* confusing. What is foo? It should have been: @SerializeAs("foo") int y; "foo" is the name "y" will be serialized with. Just to show an example with an attribute accepting a value. Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? How does any of this tell you how to serialize an int? How is Base.c also a NonSerialized with c in a superclass of it? This example might not have been the best one. I might not know that "Sub" is marked as "NonSerialized". An instance of "Sub" can be part of another class that is not marked as "NonSerialized". "serialize" would be the function that performs the serialization. I cannot write a whole serialization in a newsgroup message, can I :) This example also shows that "NonSerialized" can be applied to individual fields of a class. This tell how to serialize an int. It tells if a part of an object hierarchy (class, or field) should be serialized or not. ?? Maybe this is why I don't much care for attributes - it's all just a fog to me what is happening. I think it's quite clear what is happening. But I've might squeezed in too much in a too small example. -- /Jacob Carlborg
Re: Proposal: user defined attributes
dennis luehring wrote: i don't get the GC relation here? all attribute values are static const - because they are type-related (static) and read-only, attributes are type orientated not instance orientated C# doesn't support free-types (everything's wrapped up in classes) so the technique isn't going to be identical. In D, you'd need to be able to declare an attribute on virtually any entity declaration and have the compiler dish out the appropriate code. Trove's suggesting that the compiler simply looks up user-defined functions associated with and inject the code into the appropriate place, which I think is a good idea. The problem I see is how to do more advanced structural changes like C# does with [FieldOffset(0)]. Things like: @Int.Fast int index; assert(index.sizeof == int.sizeof) // always? which might break the type system, so I'm not sure it's even possible. The compiler might have passed the point of no-return with such attributes. Regardless, I think was Trove's suggesting would work well.
Re: Proposal: user defined attributes
On 19 March 2012 08:46, dennis luehring wrote: > > attributes does not containing code - there just a (at-runtime) queryable > information that can be attached to serveral things (like classes, methods, > ...) - think of it like double.epsilon - but extendable by users - thats > it, and in the c# world these attribute-definitions tend to be something > like an class (but without code) > > in c# you can walk by (runtime)reflection through your code and find out > if something is annotated with an special attribute and use the configure > information and do something with it - call an constructor, open an > connection, generated code (at runtime) - whatever you want > > its a easy-to-use-buildin-**attribution-system thats it - and people like > them because c# do all the big magic by giving developers a bunch of > attributes that are then used for stuff like serialization, memory-layout, > ... > > a compiletime example of this could be: > > attribute my_special_attribute > { > int version; > } > > attribute my_special_attribute2 > { > string test; > } > > class test > { > [my_special_attribute(version=**2)] > int method1(); > > [my_special_attribute(version=**2)] > [my_special_attribute2(test="**bert")] > int method2(); > } > > void main() > { > auto b = [ __traits(allMembers, D) ]; > foreach( auto a; b ) > { >-->attribute query magic >-->auto c = [ __traits(attribute("my_**special_attribute", a) ]; >-->auto c = [ __traits(attribute("my_**special_attribute2", a) ]; > >//now we know all methods with my_special_attribute >//and speical_special_attribute2 and their content (version=2 >//and test="bert" > >//now think of an template or mixing that uses this >//information for code-generation or something like that > >//thats all > } > } > +1 this post
Re: Proposal: user defined attributes
On 2012-03-19 09:01, Tove wrote: Well I was thinking if we can go one step further than C#, because of D:s CTFE... by introducing a call back from the D compiler to the library CTFE attribute handler... this way we can hide all reflection from the "end user"... and the compiler doesn't need to know anything at all, as the library does the semantic lowering. @GC.NoScan int value; @GC this() {} Compiler Asks library for transformation of unknown @GC bool library("@GC this() {anything...}") -> if the library succeeds it would then transform the string and hand back a lowered mixin to the compiler. mixin(" this() { auto b = [ __traits(allMembers, D) ]; foreach( auto a; b) {DO.GC.Stuff...} anything... } "); That would be cool. -- /Jacob Carlborg
Re: Proposal: user defined attributes
Am 19.03.2012 10:03, schrieb F i L: dennis luehring wrote: i don't get the GC relation here? all attribute values are static const - because they are type-related (static) and read-only, attributes are type orientated not instance orientated C# doesn't support free-types (everything's wrapped up in classes) so the technique isn't going to be identical. In D, you'd need to be able to declare an attribute on virtually any entity declaration and have the compiler dish out the appropriate code. Trove's suggesting that the compiler simply looks up user-defined functions associated with and inject the code into the appropriate place, which I think is a good idea. The problem I see is how to do more advanced structural changes like C# does with [FieldOffset(0)]. Things like: @Int.Fast int index; assert(index.sizeof == int.sizeof) // always? which might break the type system, so I'm not sure it's even possible. The compiler might have passed the point of no-return with such attributes. Regardless, I think was Trove's suggesting would work well. sound to simple to fit in non trival cases
Re: Proposal: user defined attributes
On Sun, 18 Mar 2012 04:03:29 -0400, Walter Bright wrote: On 3/17/2012 10:01 PM, F i L wrote: Walter Bright wrote: My impression is it is just obfuscation around a simple lazy initialization pattern. While I can see the abstraction usefulness of compile time attribute metadata, I am having a hard time seeing what the gain is with runtime attributes over more traditional techniques. I'm not sure exactly what you mean by runtime attributes. Do you mean the ability to reflect upon attributes at runtime? I mean there is modifiable-at-runtime, instance-specific data. I don't think we should go this far with attributes. If you want to store instance-specific data, we already have a place for that. I haven't been exactly groking all of this thread, but I understand what attributes are useful for having used them quite a bit in C#. Again, I am just not seeing the leap in power with this. It's a mystery to me how a user defined "attribute class" is different in any way from a user defined class, and what advantage special syntax gives a standard pattern for lazy initialization, and why extra attribute fields can't be just, well, fields. The advantage is it hooks you into the compiler's generation of metadata and runtime type information (i.e. TypeInfo). It basically allows you to describe your type in ways that the compiler doesn't natively support. It's purely a type-description thing, I think it has nothing to do with instances. The serializable example is probably most used because it's one of the most commonly used attributes in C#/Java. Given that neither has templates, the impact is somewhat greater than in D, but I believe Jacob has quite a bit of experience with serialization of types given that he wrote a serializer for D, so he would be the one I'd ask as to why it's better. I think another great example is data you can pass to the GC (if we ever get precise scanning). In a previous life, while using C#, I created a "scripting" system that used objects to define what methods were run during certain test processes (the application managed the automated testing of servers remotely). The entire script was constructed based on an xml file, and the library that edited/built the script had no access or knowledge of the types it was constructing, it used pure reflection to do everything. The cool thing (in my mind at least) was, I had a script builder application which "opened" the executable to find all the scripting objects. It did not need to be recompiled, nor did it directly link with a library having the script objects, because it used reflection to determine everything I needed. Some specific attributes weren't available in reflection, so I just added some user-defined attributes, and in that way, I was able to affect the metadata to pass information to the script building application. I think also you can make code more readable and easier to write with attributes, because you can specify/convey information rather than interpreting or making assumptions, or inventing types that have nothing to do with the way the type works. For example, you could do something like: struct noSerInt { int _val; alias this _val; } struct X { noSerInt x; // clue to not serialize x } This is extra complication which is not needed while using an instance of X *except* when serializing it. I think it's cleaner to put this information into the metadata instead of having to re-implement int. Compare to: struct X { @noSer int x; } Where you can safely ignore the @noSer attribute for most intents and purposes. I think that the sole purpose of attributes is compile-time generation of compile and run-time query-able data. Nothing else really makes sense to me. -Steve
Re: Proposal: user defined attributes
exactly my point - thx Am 19.03.2012 13:31, schrieb Steven Schveighoffer: On Sun, 18 Mar 2012 04:03:29 -0400, Walter Bright wrote: On 3/17/2012 10:01 PM, F i L wrote: Walter Bright wrote: My impression is it is just obfuscation around a simple lazy initialization pattern. While I can see the abstraction usefulness of compile time attribute metadata, I am having a hard time seeing what the gain is with runtime attributes over more traditional techniques. I'm not sure exactly what you mean by runtime attributes. Do you mean the ability to reflect upon attributes at runtime? I mean there is modifiable-at-runtime, instance-specific data. I don't think we should go this far with attributes. If you want to store instance-specific data, we already have a place for that. I haven't been exactly groking all of this thread, but I understand what attributes are useful for having used them quite a bit in C#. Again, I am just not seeing the leap in power with this. It's a mystery to me how a user defined "attribute class" is different in any way from a user defined class, and what advantage special syntax gives a standard pattern for lazy initialization, and why extra attribute fields can't be just, well, fields. The advantage is it hooks you into the compiler's generation of metadata and runtime type information (i.e. TypeInfo). It basically allows you to describe your type in ways that the compiler doesn't natively support. It's purely a type-description thing, I think it has nothing to do with instances. The serializable example is probably most used because it's one of the most commonly used attributes in C#/Java. Given that neither has templates, the impact is somewhat greater than in D, but I believe Jacob has quite a bit of experience with serialization of types given that he wrote a serializer for D, so he would be the one I'd ask as to why it's better. I think another great example is data you can pass to the GC (if we ever get precise scanning). In a previous life, while using C#, I created a "scripting" system that used objects to define what methods were run during certain test processes (the application managed the automated testing of servers remotely). The entire script was constructed based on an xml file, and the library that edited/built the script had no access or knowledge of the types it was constructing, it used pure reflection to do everything. The cool thing (in my mind at least) was, I had a script builder application which "opened" the executable to find all the scripting objects. It did not need to be recompiled, nor did it directly link with a library having the script objects, because it used reflection to determine everything I needed. Some specific attributes weren't available in reflection, so I just added some user-defined attributes, and in that way, I was able to affect the metadata to pass information to the script building application. I think also you can make code more readable and easier to write with attributes, because you can specify/convey information rather than interpreting or making assumptions, or inventing types that have nothing to do with the way the type works. For example, you could do something like: struct noSerInt { int _val; alias this _val; } struct X { noSerInt x; // clue to not serialize x } This is extra complication which is not needed while using an instance of X *except* when serializing it. I think it's cleaner to put this information into the metadata instead of having to re-implement int. Compare to: struct X { @noSer int x; } Where you can safely ignore the @noSer attribute for most intents and purposes. I think that the sole purpose of attributes is compile-time generation of compile and run-time query-able data. Nothing else really makes sense to me. -Steve
Re: Proposal: user defined attributes
On Monday, 19 March 2012 at 00:41:44 UTC, Walter Bright wrote: Maybe this is why I don't much care for attributes - it's all just a fog to me what is happening. Maybe this will help: http://research.microsoft.com/en-us/um/people/cszypers/events/WCOP2006/rouvoy-wcop-06.pdf Attribute-Oriented Programming (@OP) is a program-level marking technique. Basically, this approach allows developers to mark program elements (e.g., classes, methods, and fields) with annotations to indicate that they maintain application specific or domain-specific concerns. For example, a developer may define a logging annotation and associate it with a method to indicate that the calls to this method should be logged, or may define a web service annotation and associate it with a class to indicate that the class should implement a Web Service. Annotations separate application’s business logic from middleware-specific or domain-specific concerns (e.g., logging and web service functions). By hiding the implementation details of those semantics from program code, annotations increase the level of programming abstraction and reduce programming complexity, resulting in simpler and more readable programs. The program elements associated with annotations are transformed to more detailed program code by a supporting generation engine. For example, a generation engine may insert logging code into the methods associated with a logging annotation. Dependencies on the underlying middleware are thus replaced by annotations, acting as weak references — i.e., references that are not mandatory for the application. This means that the evolution of the underlying middleware is taken into account by the generation engine and let the program code unchanged.
Re: Proposal: user defined attributes
On 2012-03-19 13:31, Steven Schveighoffer wrote: On Sun, 18 Mar 2012 04:03:29 -0400, Walter Bright I mean there is modifiable-at-runtime, instance-specific data. I don't think we should go this far with attributes. If you want to store instance-specific data, we already have a place for that. I haven't been exactly groking all of this thread, but I understand what attributes are useful for having used them quite a bit in C#. I agree. Again, I am just not seeing the leap in power with this. It's a mystery to me how a user defined "attribute class" is different in any way from a user defined class, and what advantage special syntax gives a standard pattern for lazy initialization, and why extra attribute fields can't be just, well, fields. The advantage is it hooks you into the compiler's generation of metadata and runtime type information (i.e. TypeInfo). It basically allows you to describe your type in ways that the compiler doesn't natively support. It's purely a type-description thing, I think it has nothing to do with instances. The serializable example is probably most used because it's one of the most commonly used attributes in C#/Java. Given that neither has templates, the impact is somewhat greater than in D, but I believe Jacob has quite a bit of experience with serialization of types given that he wrote a serializer for D, so he would be the one I'd ask as to why it's better. I think another great example is data you can pass to the GC (if we ever get precise scanning). For the serialization example I think it's mostly a syntactic enhancement. It would also be an enhancement when accessing the attributes. class Foo { int a; @NonSerialized int b; } class Bar { int a; int b; mixin NonSerialized!(b); } The advantage the attribute has is: * Better syntax, more readable * Shows up in the documentation of "b". * Can be repeated on several fields (with the mixin you can only mixin "NonSerialized" once) * Easier to access the attribute * No information is added to the type itself. It would be added to the metadata of the type, i.e. TypeInfo But I see many other cases where attributes would work better than mixins. In a previous life, while using C#, I created a "scripting" system that used objects to define what methods were run during certain test processes (the application managed the automated testing of servers remotely). The entire script was constructed based on an xml file, and the library that edited/built the script had no access or knowledge of the types it was constructing, it used pure reflection to do everything. The cool thing (in my mind at least) was, I had a script builder application which "opened" the executable to find all the scripting objects. It did not need to be recompiled, nor did it directly link with a library having the script objects, because it used reflection to determine everything I needed. Some specific attributes weren't available in reflection, so I just added some user-defined attributes, and in that way, I was able to affect the metadata to pass information to the script building application. I think also you can make code more readable and easier to write with attributes, because you can specify/convey information rather than interpreting or making assumptions, or inventing types that have nothing to do with the way the type works. For example, you could do something like: struct noSerInt { int _val; alias this _val; } struct X { noSerInt x; // clue to not serialize x } This is extra complication which is not needed while using an instance of X *except* when serializing it. I think it's cleaner to put this information into the metadata instead of having to re-implement int. Compare to: struct X { @noSer int x; } Where you can safely ignore the @noSer attribute for most intents and purposes. I think that the sole purpose of attributes is compile-time generation of compile and run-time query-able data. Nothing else really makes sense to me. -Steve Very well explained. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 3/19/12, Jacob Carlborg wrote: > * Can be repeated on several fields (with the mixin you can only mixin > "NonSerialized" once) When I implemented NonSerialized for Vladimir's json library he made a suggestion to simply create enums of each field that is not to be serialized and encode it as "fieldname_nonSerialized". That would enable using a NonSerialized mixin multiple times. I've yet to implement it in that way, I ran into some odd bugs but I'll have a look at this soon. My implementation used a hash lookup table for the fields, but using enums would make the code even simpler. Basically: struct Foo { int x; string name; mixin(NonSerialized!name); string lastName; mixin(NonSerialized!lastName); } and this would expand to: struct Foo { int x; string name; enum name_nonSerialized; string lastName; enum lastName_nonSerialized; } So all you'd have to do is use compile-time introspection and a little bit of string processing to figure out if a field should be serialized or not.
Re: Proposal: user defined attributes
On Monday, 19 March 2012 at 20:44:43 UTC, Andrej Mitrovic wrote: On 3/19/12, Jacob Carlborg wrote: * Can be repeated on several fields (with the mixin you can only mixin "NonSerialized" once) When I implemented NonSerialized for Vladimir's json library he made a suggestion to simply create enums of each field that is not to be serialized and encode it as "fieldname_nonSerialized". That would enable using a NonSerialized mixin multiple times. I've yet to implement it in that way, I ran into some odd bugs but I'll have a look at this soon. My implementation used a hash lookup table for the fields, but using enums would make the code even simpler. Basically: struct Foo { int x; string name; mixin(NonSerialized!name); string lastName; mixin(NonSerialized!lastName); } and this would expand to: struct Foo { int x; string name; enum name_nonSerialized; string lastName; enum lastName_nonSerialized; } So all you'd have to do is use compile-time introspection and a little bit of string processing to figure out if a field should be serialized or not. I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members?
Re: Proposal: user defined attributes
On 3/19/12, F i L wrote: > Also, if objects are not identified as > being unique marked (in the compilers eyes), what specific > attribute post-fixes will it be searching for on enums members? I'm really not talking about general-purpose attributes, I was commenting on a specific serialization example. :) Also I've no idea what "objects being unique marked" means.
Re: Proposal: user defined attributes
On 3/19/12 3:44 PM, Andrej Mitrovic wrote: On 3/19/12, Jacob Carlborg wrote: * Can be repeated on several fields (with the mixin you can only mixin "NonSerialized" once) When I implemented NonSerialized for Vladimir's json library he made a suggestion to simply create enums of each field that is not to be serialized and encode it as "fieldname_nonSerialized". That would enable using a NonSerialized mixin multiple times. I've yet to implement it in that way, I ran into some odd bugs but I'll have a look at this soon. My implementation used a hash lookup table for the fields, but using enums would make the code even simpler. Basically: struct Foo { int x; string name; mixin(NonSerialized!name); string lastName; mixin(NonSerialized!lastName); } and this would expand to: struct Foo { int x; string name; enum name_nonSerialized; string lastName; enum lastName_nonSerialized; } So all you'd have to do is use compile-time introspection and a little bit of string processing to figure out if a field should be serialized or not. I salute creative uses of the language over defining new features. Andrei
Re: Proposal: user defined attributes
On 3/19/12 3:55 PM, F i L wrote: I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members? Not a big issue, the name could always contain a uuid which makes collision practically impossibile. Andrei
Re: Proposal: user defined attributes
On Monday, 19 March 2012 at 21:00:32 UTC, Andrei Alexandrescu wrote: On 3/19/12 3:55 PM, F i L wrote: I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members? Not a big issue, the name could always contain a uuid which makes collision practically impossibile. Andrei So the compiler would always search for enums with a specific "--Mxxx-Nxxx-" signature? Guess that could work.
Re: Proposal: user defined attributes
On Mon, Mar 19, 2012 at 04:00:00PM -0500, Andrei Alexandrescu wrote: > On 3/19/12 3:44 PM, Andrej Mitrovic wrote: [...] > >So all you'd have to do is use compile-time introspection and a > >little bit of string processing to figure out if a field should be > >serialized or not. > > I salute creative uses of the language over defining new features. +1. T -- Life is too short to run proprietary software. -- Bdale Garbee
Re: Proposal: user defined attributes
Andrej Mitrovic wrote: Also I've no idea what "objects being unique marked" means. I meant that Attribute metadata is distinct data in the compilers eyes, ie, no name magic, just attribute lookup.
Re: Proposal: user defined attributes
On 2012-03-19 21:44, Andrej Mitrovic wrote: When I implemented NonSerialized for Vladimir's json library he made a suggestion to simply create enums of each field that is not to be serialized and encode it as "fieldname_nonSerialized". That would enable using a NonSerialized mixin multiple times. I've yet to implement it in that way, I ran into some odd bugs but I'll have a look at this soon. My implementation used a hash lookup table for the fields, but using enums would make the code even simpler. Basically: struct Foo { int x; string name; mixin(NonSerialized!name); string lastName; mixin(NonSerialized!lastName); } and this would expand to: struct Foo { int x; string name; enum name_nonSerialized; string lastName; enum lastName_nonSerialized; } So all you'd have to do is use compile-time introspection and a little bit of string processing to figure out if a field should be serialized or not. Yeah, but that will complicate the retrieval of the information. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 2012-03-19 22:00, Andrei Alexandrescu wrote: I salute creative uses of the language over defining new features. Andrei Sure, just as well as you can do object oriented programming in C, but it is a mess. So is this. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 3/19/12, Jacob Carlborg wrote: > Yeah, but that will complicate the retrieval of the information. What is so complicated about extracting fields? Just iterate via .tupleof: module test; import std.stdio; import std.conv; struct Foo { int x; string name; mixin NonSerialized!name; string lastName; mixin NonSerialized!lastName; string extra; } mixin template NonSerialized(alias field) { mixin("enum __attribute_nonSerialized_" ~ field.mangleof ~ ";"); } string serialize(T)(T input) { string result; foreach (i, field; input.tupleof) { static if (skipSerialize!(T, input.tupleof[i].mangleof)) result ~= to!string(typeof(field).init) ~ "\n"; else result ~= to!string(field) ~ "\n"; } return result; } template skipSerialize(T, string mangle) { enum bool skipSerialize = __traits(hasMember, T, "__attribute_nonSerialized_" ~ mangle); } void main() { Foo foo = Foo(10, "Foo", "Bar", "Doo"); string bin = serialize(foo); writeln(bin); } And by using .init instead of just skipping serialization altogether you can unserialize at a later point even if you end up removing some of the mixins, so you can have some binary-compatibility there.
Re: Proposal: user defined attributes
On Monday, 19 March 2012 at 21:00:32 UTC, Andrei Alexandrescu wrote: On 3/19/12 3:55 PM, F i L wrote: I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members? Not a big issue, the name could always contain a uuid which makes collision practically impossibile. Andrei And with parameters? Or how about run-time reflection, which is something that should be added eventually for attributes as well (that is, typeid(Blah).getCustomAttributes())? We can't manually add things into the TypeInfo. This is an already ridiculously hackish approach, and it *does not* work for anything besides trivial applications. It is completly unreasonable to expect everything to be done in a library; the compiler exists for a reason and at some point you have to draw the line. Why even bother having an auto keyword? Instead of 'auto a = b + c' you could simply use 'Auto!(b + c) a = b + c'. It is a more extreme example for now, but won't be too much different once more complicated things arise; after all, auto!2 a = 2 is not much different from auto a = 2. Just like it's not too much different for parameterless attributes (even if it is uglier and much more hackish), but once you get into parameters and runtime stuff it becomes just as ugly as the above example.
Re: Proposal: user defined attributes
and how to add attribute parameters like DoSerialize(type=packed) for example - very very common in C# attributes and java annotations http://en.wikipedia.org/wiki/Java_annotation Am 19.03.2012 22:00, schrieb Andrei Alexandrescu: On 3/19/12 3:44 PM, Andrej Mitrovic wrote: On 3/19/12, Jacob Carlborg wrote: * Can be repeated on several fields (with the mixin you can only mixin "NonSerialized" once) When I implemented NonSerialized for Vladimir's json library he made a suggestion to simply create enums of each field that is not to be serialized and encode it as "fieldname_nonSerialized". That would enable using a NonSerialized mixin multiple times. I've yet to implement it in that way, I ran into some odd bugs but I'll have a look at this soon. My implementation used a hash lookup table for the fields, but using enums would make the code even simpler. Basically: struct Foo { int x; string name; mixin(NonSerialized!name); string lastName; mixin(NonSerialized!lastName); } and this would expand to: struct Foo { int x; string name; enum name_nonSerialized; string lastName; enum lastName_nonSerialized; } So all you'd have to do is use compile-time introspection and a little bit of string processing to figure out if a field should be serialized or not. I salute creative uses of the language over defining new features. Andrei
Re: Proposal: user defined attributes
On 2012-03-19 22:51, Andrej Mitrovic wrote: On 3/19/12, Jacob Carlborg wrote: Yeah, but that will complicate the retrieval of the information. What is so complicated about extracting fields? Just iterate via .tupleof: It wasn't actually that much more complicated. But now there is one extra enum for each NonSerialized field. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 2012-03-19 22:00, Andrei Alexandrescu wrote: I salute creative uses of the language over defining new features. Andrei The actual point of user defined attributes it to be able to create domain specific attributes so we don't have to add new features to the language. This is also to have a sane syntax for the attributes. I think in several cases D could have chose to implement a more general feature but instead implemented a very specific feature or hack. Example: If D supported passing delegates to a function after the function call several language features could have been implemented in the library instead. void synchronized (void delegate () dg) { try { lock(); dg(); } finally unlock(); } synchronized { // do something } In the same way foreach can be implemented in a library function: void foreach (T) (T[] arr, void delegate (T) dg) { for (size_t i = 0; i < arr.length; i++) dg(arr[i]); } auto arr = [3, 4, 5]; foreach (arr ; e // this is the parameter to the delegate) { writeln(e); } -- /Jacob Carlborg
Re: Proposal: user defined attributes
Jacob Carlborg wrote: If D supported passing delegates to a function after the function call several language features could have been implemented in the library instead. void synchronized (void delegate () dg) { try { lock(); dg(); } finally unlock(); } synchronized { // do something } In the same way foreach can be implemented in a library function: void foreach (T) (T[] arr, void delegate (T) dg) { for (size_t i = 0; i < arr.length; i++) dg(arr[i]); } auto arr = [3, 4, 5]; foreach (arr ; e // this is the parameter to the delegate) { writeln(e); } That's pretty slick. D would need delegate inlining + @forceInline before foreach could be expressed this way though.
Re: Proposal: user defined attributes
On 2012-03-20 10:49, F i L wrote: That's pretty slick. D would need delegate inlining + @forceInline before foreach could be expressed this way though. Yes, but currently, as far as I know, the delegate passed to opApply is not inlined. -- /Jacob Carlborg
Re: Proposal: user defined attributes
On 3/20/12 12:50 AM, Kapps wrote: On Monday, 19 March 2012 at 21:00:32 UTC, Andrei Alexandrescu wrote: On 3/19/12 3:55 PM, F i L wrote: I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members? Not a big issue, the name could always contain a uuid which makes collision practically impossibile. Andrei And with parameters? Or how about run-time reflection, which is something that should be added eventually for attributes as well (that is, typeid(Blah).getCustomAttributes())? We can't manually add things into the TypeInfo. Perhaps we should add a field of type Variant[string]. This is an already ridiculously hackish approach, and it *does not* work for anything besides trivial applications. It is completly unreasonable to expect everything to be done in a library; the compiler exists for a reason and at some point you have to draw the line. I'm afraid I disagree. A targeted language feature definitely makes a library approach inferior, by definition. But adding features is cheating, like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". I'm not saying this particular feature should or should not be in the language, but I wish our community exercised considerably more restraint when it comes about adding new language features. Why even bother having an auto keyword? Instead of 'auto a = b + c' you could simply use 'Auto!(b + c) a = b + c'. It is a more extreme example for now, but won't be too much different once more complicated things arise; after all, auto!2 a = 2 is not much different from auto a = 2. Just like it's not too much different for parameterless attributes (even if it is uglier and much more hackish), but once you get into parameters and runtime stuff it becomes just as ugly as the above example. I don't think your example with auto is relevant. Andrei
Re: Proposal: user defined attributes
On 3/20/12 1:22 AM, dennis luehring wrote: and how to add attribute parameters like DoSerialize(type=packed) for example - very very common in C# attributes and java annotations http://en.wikipedia.org/wiki/Java_annotation One more argument to the template? Andrei
Re: Proposal: user defined attributes
On 2012-03-20 16:17, Andrei Alexandrescu wrote: On 3/20/12 12:50 AM, Kapps wrote: Perhaps we should add a field of type Variant[string]. No, not Variant[string] again. This is an already ridiculously hackish approach, and it *does not* work for anything besides trivial applications. It is completly unreasonable to expect everything to be done in a library; the compiler exists for a reason and at some point you have to draw the line. I'm afraid I disagree. A targeted language feature definitely makes a library approach inferior, by definition. But adding features is cheating, like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". I'm not saying this particular feature should or should not be in the language, but I wish our community exercised considerably more restraint when it comes about adding new language features. See my reply to one of your other posts: http://forum.dlang.org/thread/bccwycoexxykfgxve...@forum.dlang.org?page=9#post-jk9gk8:242t7k:241:40digitalmars.com -- /Jacob Carlborg
Re: Proposal: user defined attributes
Andrei Alexandrescu wrote: like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. RON PAUL 2012!!! sorry, I couldn't help myself. Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". You can be creative with a sledge hammer, or you can be creative with a jack hammer. D is already a bulldozer, but that doesn't mean it shouldn't become a wreaking ball. ;-)
Re: Proposal: user defined attributes
On Tue, 20 Mar 2012 11:17:02 -0400, Andrei Alexandrescu wrote: Perhaps we should add a field of type Variant[string]. 1. Variant is not (and shouldn't be IMO) part of druntime. 2. This is *static* data that should be available at compile time. D's runtime wasting cycles filling in static data (including lots of heap allocations) seems like a big enough detriment that compiler help is warranted. This is an already ridiculously hackish approach, and it *does not* work for anything besides trivial applications. It is completly unreasonable to expect everything to be done in a library; the compiler exists for a reason and at some point you have to draw the line. I'm afraid I disagree. A targeted language feature definitely makes a library approach inferior, by definition. But adding features is cheating, like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. Not exactly. We could all be writing code in assembly if "adding features" was always caustic. What is nice about adding this feature is it provides a custom solution to hooking the compiler's TypeInfo generation. We are setting up the compiler to give us hooks so we *don't* have to extend the compiler every time we want new reflection features. One of the oft-requested features of D is reflection capability. The answer is generally that we have compile-time reflection, which can theoretically be used to build runtime reflection. However, the rebuttal I always come back with is "yeah, but why should I build at runtime that which is obvious at compile time?" Note that one library that did attempt runtime reflection capability (flectioned) does all this at runtime, and does some really funky shit, like opening /proc/self/map on Linux, or requiring you to pass an OPTLINK map file. I don't look at these as "innovations" as much as I do as workarounds. Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". I have to disagree for this instance, the barrier to creating reflection data from compile-time info is very large. If anything, this *expands* the ability to create, since you now have a new way to pass information from compiler to runtime. -Steve
Re: Proposal: user defined attributes
On 3/20/12 10:52 AM, Jacob Carlborg wrote: On 2012-03-20 16:17, Andrei Alexandrescu wrote: On 3/20/12 12:50 AM, Kapps wrote: Perhaps we should add a field of type Variant[string]. No, not Variant[string] again. Why? I thought it was agreed that that's a good idea for exceptions. I'm not saying this particular feature should or should not be in the language, but I wish our community exercised considerably more restraint when it comes about adding new language features. See my reply to one of your other posts: http://forum.dlang.org/thread/bccwycoexxykfgxve...@forum.dlang.org?page=9#post-jk9gk8:242t7k:241:40digitalmars.com I understand the intention there, but my point stands: let's first explore doing it in the language, and advocate a new feature only when that fails. We've been too trigger-happy about proposing features even for the most trivial inconveniences. Andrei
Re: Proposal: user defined attributes
On 3/20/12 11:09 AM, Steven Schveighoffer wrote: On Tue, 20 Mar 2012 11:17:02 -0400, Andrei Alexandrescu wrote: Perhaps we should add a field of type Variant[string]. 1. Variant is not (and shouldn't be IMO) part of druntime. 2. This is *static* data that should be available at compile time. D's runtime wasting cycles filling in static data (including lots of heap allocations) seems like a big enough detriment that compiler help is warranted. Forgot to mention - I snipped these points because I agree with them. Andrei
Re: Proposal: user defined attributes
On 3/20/12 11:09 AM, Steven Schveighoffer wrote: On Tue, 20 Mar 2012 11:17:02 -0400, Andrei Alexandrescu wrote: I'm afraid I disagree. A targeted language feature definitely makes a library approach inferior, by definition. But adding features is cheating, like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. Not exactly. We could all be writing code in assembly if "adding features" was always caustic. This is trivializing my point. Please. What is nice about adding this feature is it provides a custom solution to hooking the compiler's TypeInfo generation. We are setting up the compiler to give us hooks so we *don't* have to extend the compiler every time we want new reflection features. There is something nice about every new feature. One of the oft-requested features of D is reflection capability. The answer is generally that we have compile-time reflection, which can theoretically be used to build runtime reflection. However, the rebuttal I always come back with is "yeah, but why should I build at runtime that which is obvious at compile time?" I thought there were discussions that didn't add runtime overhead. Note that one library that did attempt runtime reflection capability (flectioned) does all this at runtime, and does some really funky shit, like opening /proc/self/map on Linux, or requiring you to pass an OPTLINK map file. I don't look at these as "innovations" as much as I do as workarounds. Maybe there's a better approach than flectioned. Consider the language is frozen solid. How would you solve problems with it? Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". I have to disagree for this instance, the barrier to creating reflection data from compile-time info is very large. If anything, this *expands* the ability to create, since you now have a new way to pass information from compiler to runtime. I hope I'll be convinced. Andrei
Re: Proposal: user defined attributes
On Tuesday, 20 March 2012 at 15:17:04 UTC, Andrei Alexandrescu wrote: Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. I agree entirely. Usually, when I see threads like this, my response is "challenge accepted". But, on this problem, my answer is, unfortunately, "challenge failed". I want to annotate declarations for my web.d, where you can write a class and have D do a bunch of work for you in creating all kinds of stuff. Let me do up a quick example: === struct MyType { int num; string name; string desc; Element makeHtmlElement() { auto e = Element.make("div", desc).addClass("my-type"); return e; } } class MySite : ApiProvider { MyType getSomething(int someNumber, string name, Text description) { return MyType(someNumber, name, description); } void savePhoneNumber(string name, string phoneNumber) { _checkLoggedIn(); ensureGoodPost(); _doSave(); } void _doSave() { yada yada yada } } === Now, when you go to mysite.com/get-something, it will generate a form like this: Some Number: Name: Description: [Get Something] It pulls this info from the D code - it uses an alias template param to the method, then parses .stringof to get the names and default params. (It then mixes in the default to get a D type, which doesn't work on custom types since they aren't in the right scope, but hey, it works in a lot of cases.) When possible, it uses the type of the parameter to specialize the form. This comes from ParameterTypeTuple. Here, it recognizes struct Text{} as being a textarea. tbh, I'd prefer to use @note(Textarea(rows)), but this works, and alias this to string makes it pretty natural to work with too. Moreover, I wrote method="GET". It pulls this from the method name. Since it starts with get, it doesn't require http post for it. So far, so good. Let's look at the next method, savePhoneNumber. This !startsWith("get"), so it generates a POST form, with the same kind of thing: Name: _ Phone Number: _ [Save Phone Number] Hey, it works. But, I'd like to do even better. Could we do validation? Well, yeah, I think we could. struct PhoneNumber { enum _validationRegex = "[0-9]+"; } Boom. What about an example text, though? You could use that same enum method, but you would need a different type for each example. If you have two "string name" and in one case, you want it to be "e.g. Bob Smith" and in the other, you want "e.g. Downtown Office", you'd have to make separate structs for them, despite it just being strings in every other way. That's one big case where the compile time annotation comes through: void savePhoneNumber @note(ExampleText("e.g. Downtown Office") string name, PhoneNumber phoneNumber) { } To do that with a mixin, you might: mixin(ExampleText!(savePhoneNumber, "name", "downtown")); void savePhoneNumber(string name, ...) {...} and have that yield: enum _attribute_DsavePhoneNumberMangle_param_name_FILE_LINE_type = ExampleText("downtown"); ok, this is a bit of a pain in the ass, but I think it'd work... (the file_line_type stuff is so you can have multiple things of the same type. Moderately fragile! But, it'd work.) The pain gets bad down the line though. Renaming things means repetition. Separate declarations might get lost as you shuffle the order around. But, not too awful... Until you get into more functions. Enter arsd.web.prepareReflection and makeJavascriptApi: foreach(member; __traits(allMembers, yourclass)) // build a runtime map and corresponding bindings for other languages Should our enum be included here? Should this include code to detect the annotations and translate them to the native target language? How much code is this going to take? What if I use a third party lib? Will it have to be hacked to ignore these extra names too? Well, we can work around this too. web.d has a convention where static if(name[0] == '_') { don't process }. (This is actually a workaround for a lack of __traits(getProtection) though. We already have D keywords that do this: public and/or export. But, there's currently no way to check for these, so I settled for a naming convention. This is what _doSave() demonstrates in the example. I'm hoping to do a dmd pull request to add getProtection at some point though.) We could all agree on a naming convention, in theory. In practice, I don't know. If I could check export || public, I might drop the underscore. Another problem is how do we get this data? We have an alias of the method... but not it's parent. Well, there's __traits(getParent). I think we could actually do that. But the idea of a parent reminds me of another problem. This is a class, the method is virtu
Re: Proposal: user defined attributes
On 03/20/2012 05:31 PM, Adam D. Ruppe wrote: Even /ignoring/ them takes a lot code, and that's what, to me, pushes it over into compiler territory. vote++
Re: Proposal: user defined attributes
Andrei Alexandrescu wrote: On 3/20/12 10:52 AM, Jacob Carlborg wrote: On 2012-03-20 16:17, Andrei Alexandrescu wrote: On 3/20/12 12:50 AM, Kapps wrote: Perhaps we should add a field of type Variant[string]. No, not Variant[string] again. Why? I thought it was agreed that that's a good idea for exceptions. Please, do not transform D into a dynamic language.
Re: Proposal: user defined attributes
On 3/20/12 2:04 PM, Piotr Szturmaj wrote: Andrei Alexandrescu wrote: On 3/20/12 10:52 AM, Jacob Carlborg wrote: On 2012-03-20 16:17, Andrei Alexandrescu wrote: On 3/20/12 12:50 AM, Kapps wrote: Perhaps we should add a field of type Variant[string]. No, not Variant[string] again. Why? I thought it was agreed that that's a good idea for exceptions. Please, do not transform D into a dynamic language. Where's the "dynamic languages rok" crowd when you need it :o). Andrei
Re: Proposal: user defined attributes
Le 20/03/2012 16:17, Andrei Alexandrescu a écrit : On 3/20/12 12:50 AM, Kapps wrote: On Monday, 19 March 2012 at 21:00:32 UTC, Andrei Alexandrescu wrote: On 3/19/12 3:55 PM, F i L wrote: I think this could get tricky for the compiler to confidently use given that the mixed in enums can collide with existing members (although not likely). Also, if objects are not identified as being unique marked (in the compilers eyes), what specific attribute post-fixes will it be searching for on enums members? Not a big issue, the name could always contain a uuid which makes collision practically impossibile. Andrei And with parameters? Or how about run-time reflection, which is something that should be added eventually for attributes as well (that is, typeid(Blah).getCustomAttributes())? We can't manually add things into the TypeInfo. Perhaps we should add a field of type Variant[string]. This is an already ridiculously hackish approach, and it *does not* work for anything besides trivial applications. It is completly unreasonable to expect everything to be done in a library; the compiler exists for a reason and at some point you have to draw the line. I'm afraid I disagree. A targeted language feature definitely makes a library approach inferior, by definition. But adding features is cheating, like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects. Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer". I'm not saying this particular feature should or should not be in the language, but I wish our community exercised considerably more restraint when it comes about adding new language features. That feature has been added to java with great benefit. I think the underlying need here is AOP. Adding annotation to java had great benefice in introducing AOP capabilities to the language. See : http://projectlombok.org/ Considering that D has great compile time capabilities, this is somewhere we want to go. Additionnaly, this is something that remove other capabilities, and replace them by lib support. For example, with @synchronized, I could specify the phobos that I want that method or class to be synchronized, and the lib is able to add the needed code to ensure that functionality at compile time. I have to say that the whole idea of attaching property to instance doesn't make any sense to me - Walter make a good point on that I think, so I will not repeat his arguments.