digitalmars.D - Custom attributes (again)
- Manu (44/44) Apr 05 2012 I just want to add more real-world experience to the controversy.
- Paulo Pinto (57/57) Apr 05 2012 charset="UTF-8"
- Manu (9/11) Apr 05 2012 I don't think it'd suit my purposes implemented as an interface for a
- bearophile (6/9) Apr 05 2012 There are other interesting ways to conceive attributes. I think
- Walter Bright (8/10) Apr 05 2012 At the Lang.NEXT conference over the last 3 days, I was able to talk to ...
- deadalnix (2/14) Apr 05 2012 They should be attached to declarations.
- Andrei Alexandrescu (4/20) Apr 05 2012 The question was whether the declaration affects the type of the
- Steven Schveighoffer (12/33) Apr 05 2012 n
- Timon Gehr (3/24) Apr 05 2012 Ideally it would be powerful enough to allow changing the type, but most...
- Walter Bright (5/7) Apr 05 2012 Having it perturb the type implies a huge swamp of how that affects the
- deadalnix (7/14) Apr 05 2012 I did some hacking into dmd in that regard, and I can confirm this is
- Manu (7/40) Apr 06 2012 e
- Jacob Carlborg (8/20) Apr 05 2012 If I recall correctly, both Java annotations and C# attributes let you
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (6/26) Apr 05 2012 C#'s grammar directly encodes what metadata element the attribute is
- deadalnix (2/22) Apr 05 2012 This is bar's declaration.
- Kapps (18/31) Apr 05 2012 I'm not sure if I'm understanding this correctly, but by
- Ary Manzana (19/29) Apr 05 2012 I don't understand the difference between "storage class" and "type
- Jacob Carlborg (10/28) Apr 06 2012 I would like to have the possibility to attach attributes to types and
- Timon Gehr (3/10) Apr 06 2012 @not_null cannot be attached to "Foo". It would have to create a new
- Jacob Carlborg (4/6) Apr 06 2012 Hmm, I guess. But it would be nice to have :)
- Piotr Szturmaj (10/17) Apr 06 2012 Do you mean return type? I think your syntax has some serious
- Manu (6/26) Apr 06 2012 There's no need to attribute a return value. A) I think you're confusing...
- Jacob Carlborg (4/29) Apr 06 2012 It depends on what we want out of attributes.
- Piotr Szturmaj (7/20) Apr 06 2012 See http://msdn.microsoft.com/en-us/library/b3787ac0%28v=vs.80%29.aspx
- Jacob Carlborg (13/22) Apr 06 2012 Hmm, or something like how Java does it. You attached this information
- Piotr Szturmaj (15/39) Apr 06 2012 I think that @target is a solution for simple types, but UDTs may use
- deadalnix (3/37) Apr 06 2012 As foo isn't a declaration, I don't think it is attribute we want here.
- Manu (11/24) Apr 06 2012 Yes, most certainly the former. The latter is already possible with tric...
- Timon Gehr (2/8) Apr 06 2012 @safe affects the type.
- Manu (5/14) Apr 06 2012 I realise that, I'm just suggesting this is a possible solution to the
- Jacob Carlborg (4/8) Apr 05 2012 Yes, give us custom attributes now :)
- Mike Parker (2/9) Apr 05 2012 Pretty please.
- Walter Bright (15/17) Apr 05 2012 I was thinking of something along the lines of what has been proposed he...
- Kapps (24/44) Apr 06 2012 I like it for the most part. One thing I'd like to see is placing
- Walter Bright (8/28) Apr 06 2012 Could do:
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (7/45) Apr 06 2012 It actually can be a problem. In .NET land, there are many attributes
- Walter Bright (6/9) Apr 06 2012 Perhaps a better scheme is:
- Johannes Pfau (47/64) Apr 06 2012 The last time custom attributes where discussed, a C# like model was
- Walter Bright (2/5) Apr 06 2012 C# uses a runtime implementation, not a compile time one.
- Johannes Pfau (5/11) Apr 06 2012 OK, but my post was only about the syntax, there's no runtime/compile
- Andrei Alexandrescu (9/14) Apr 06 2012 Speaking of the distinction, it would be great if we arranged things
- deadalnix (5/20) Apr 06 2012 Again, I rise the need of AOP.
- Timon Gehr (10/26) Apr 06 2012 What do you have in mind here?
- Andrei Alexandrescu (13/26) Apr 06 2012 Essentially we want to associate with any symbol (be it a type,
- Timon Gehr (21/45) Apr 06 2012 There is no existing in-language solution whose only bad property is its...
- Andrei Alexandrescu (12/27) Apr 06 2012 You can always assume fresh variables even though indeed there's no
- Steven Schveighoffer (5/19) Apr 06 2012 I don't think that applies here. We have no low-level mechanism to affe...
- Manu (2/66) Apr 06 2012 +1
- Timon Gehr (4/39) Apr 06 2012 This all seems very reasonable. I think this is how things should work.
- deadalnix (2/66) Apr 06 2012 That is a really nice proposal !
- Manu (9/92) Apr 06 2012 p://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx>
- Ary Manzana (60/71) Apr 06 2012 At least in .Net and Java it's something like this.
- Walter Bright (12/64) Apr 06 2012 This is a runtime system.
- Ary Manzana (12/107) Apr 06 2012 Yes, but I'm thinking about a compile-time system (as I showed in the
- Walter Bright (5/9) Apr 06 2012 All the semantics of @safe are in the compiler. None of it can be user d...
- Timon Gehr (5/15) Apr 06 2012 The proposal is not to make the semantics of @safe user defined. I think...
- Ary Manzana (8/26) Apr 06 2012 The compiler does the same for TypeInfo, TypeInfo_ClassDeclaration or
- Timon Gehr (20/86) Apr 06 2012 It would behave like a struct anyway. The issue is whether any struct
- Ary Manzana (4/31) Apr 06 2012 True, I struct can be fine. And I don't see any problem in using it in
- Manu (25/90) Apr 06 2012 I don't think it's necessary to declare the struct as @attribute
- Jacob Carlborg (10/14) Apr 06 2012 If you create a new symbol, i.e. "Foo" then it would obey the normal
- Jacob Carlborg (4/26) Apr 06 2012 This is much better, as I've said before.
- Manu (16/28) Apr 06 2012 What about:
- Walter Bright (4/17) Apr 06 2012 Are you really changing the arguments for every declaration? Or is it on...
- Timon Gehr (11/33) Apr 06 2012 Yes, allowing the arguments to be different is a crucial feature.
- Johannes Pfau (5/22) Apr 06 2012 Or add a reserved pseudo-namespace (like e.g 'builtin') for compiler
- Piotr Szturmaj (11/18) Apr 06 2012 The same applies to other identifiers, like class named "class". NET has...
- Piotr Szturmaj (5/8) Apr 06 2012 should be:
- Manu (16/39) Apr 06 2012 Of course, what's the point otherwise? This is the very definition of
- Jacob Carlborg (4/5) Apr 06 2012 Just as we have today with keywords and symbols, I don't see the problem...
- Adam D. Ruppe (15/17) Apr 06 2012 Things like safe aren't keywords though. They are just
- Jacob Carlborg (7/23) Apr 07 2012 I mean that "int" is a keyword and "int" is in the same "scope" as the
- deadalnix (4/26) Apr 06 2012 That isn't a good argument IMO. We have type int and user defined types....
- deadalnix (3/30) Apr 06 2012 +1 I see no additional benefit for this. D have very good lookup rules
- Jacob Carlborg (4/15) Apr 06 2012 What would "3" do in this case? Be the value of the attribute?
- Jacob Carlborg (4/7) Apr 06 2012 No. See my other reply.
- Jacob Carlborg (7/14) Apr 06 2012 The way I'm thinking of attributes is that they are declared, somehow,
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (8/28) Apr 06 2012 I think this is mostly reasonable. I assume that it would be possible to...
- Bernard Helyer (7/27) Apr 06 2012 I like it. Perhaps
- Walter Bright (2/7) Apr 06 2012 That's what the hasAttribute is for.
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (4/42) Apr 06 2012 While I understand the rationale, that seems a bit too "magic"...
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (6/26) Apr 06 2012 Also, by storage class do you mean it will work only on fields?
- Walter Bright (2/3) Apr 06 2012 No. Storage classes work on fields, functions, and variables.
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (6/9) Apr 06 2012 What about type declarations? I think those ought to be supported too.
- Walter Bright (3/5) Apr 06 2012 That would make it a "type constructor", not a storage class, which we t...
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (7/14) Apr 06 2012 To be clear, I don't want annotations on a type declaration to actually
- Walter Bright (9/23) Apr 06 2012 What would an annotation on a type mean if it does not affect the type? ...
- Timon Gehr (16/47) Apr 06 2012 I don't get that either, it has to affect the type. It does not have any...
- Manu (5/16) Apr 06 2012 Yeah, I always imagined it being about that simple too... are you able t...
- Ary Manzana (3/10) Apr 06 2012 What's the difference between "type constructor" and "storage class"
- Walter Bright (3/15) Apr 06 2012 static const(int)* foo;
- Timon Gehr (6/24) Apr 06 2012 Still, the 'static' in
- deadalnix (6/24) Apr 06 2012 Why can't attribute be attached on declaration ?
- Artur Skawina (33/45) Apr 06 2012 @attr(deprecated) struct T { int blah; } // every instance of S now mark...
- Timon Gehr (7/14) Apr 06 2012 I think what was discussed there is that
- Walter Bright (15/17) Apr 06 2012 How would:
- Timon Gehr (12/32) Apr 06 2012 Yes, they are.
- Walter Bright (2/32) Apr 09 2012 But you said it was added to the *type*.
- Timon Gehr (7/43) Apr 10 2012 What I said was that it is added to the declaration. If the declaration
- Steven Schveighoffer (8/16) Apr 10 2012 I should clarify that it's *associated* with the type. It should not
- Artur Skawina (10/58) Apr 10 2012 The last one is the one i'm not sure about. What's the advantage of not ...
- Manu (6/17) Apr 06 2012 c was not attributed, and has no attributes.
- Walter Bright (2/5) Apr 09 2012 Right, they are not added to the *type*.
- deadalnix (2/7) Apr 10 2012 No, they are not, or it will become a crazy mess.
- Steven Schveighoffer (37/44) Apr 06 2012 . =
- Manu (6/44) Apr 06 2012 Just to clarify, typeof(d) and typeof(d2) (ie, both D's) are still
- Steven Schveighoffer (3/9) Apr 06 2012 Correct.
- Jacob Carlborg (5/10) Apr 06 2012 Yes, annotations/attributes should be accessible at both compile time
- Jacob Carlborg (4/7) Apr 06 2012 They need to be attachable to classes, structs, enums and so on as well.
- Manu (13/33) Apr 06 2012 I think this is unnecessarily verbose, although certainly workable as a
- Jacob Carlborg (13/33) Apr 06 2012 I'm not a particular fan of that syntax. I would go with:
- Jacob Carlborg (5/25) Apr 06 2012 Again, this is my proposal:
- Adam D. Ruppe (11/14) Apr 06 2012 The identifier in there is a liability because of
- Andrei Alexandrescu (3/19) Apr 06 2012 You also need means to enumerate attributes.
- Piotr Szturmaj (5/15) Apr 06 2012 Minimalistically getAttribute*s* should be enough:
- Adam D. Ruppe (10/11) Apr 06 2012 Note that my proposal from a couple weeks ago did it this way.
- Marco Leise (75/75) Apr 08 2012 I don't want this thread to disappear. The ideas presented here have com...
- Jacob Carlborg (6/10) Apr 08 2012 I don't see why the attributes should be accessible at runtime. Even if
- Marco Leise (5/16) Apr 08 2012 Yeah, it was supposed to mean "it requires CTFE support, runtime support...
- deadalnix (4/13) Apr 09 2012 If it is available at compile time, it is implementable at runtime as a
- Jacob Carlborg (5/8) Apr 09 2012 I'm not saying how it should be implemented, just that it should be
- Steven Schveighoffer (5/11) Apr 10 2012 I think there was some confusion, read a quote of what you said:
- Jacob Carlborg (5/18) Apr 10 2012 Yeah, I did, hehe :)
- Marco Leise (5/28) Apr 10 2012 So in the end we more or less agree that Walter and others can implement...
- Jacob Carlborg (4/5) Apr 10 2012 Something like that.
I just want to add more real-world experience to the controversy. I'm finding myself needing to use custom attributes almost every day. I have numerous systems that need to scan the module for things marked accordingly to automate bindings to their respective systems. This is my current list of attributes I want to mark things with: Export to game engine Export to script language Import from game engine ** Import from script language (tentative, I'm sure I'll need it in a few more days) Expose to editor (with additional properties; description, edit type, etc) Serialise (load/save game) Replay serialisation (a different kind of serialisation that works with different data sets) And others I've encountered in passing that I can't recall right now. As you can imagine, any attempt to 'work around' the lack of an attribute system, ie, (ab)using enums, etc as have been suggested, leads to a big mess in the context of all these requirements. Management of such lists of stuff in disconnected places in code is time consuming, thoroughly annoying, error-prone, difficult to maintain, and leaves programmers with the bitter taste of C++. Alternatively, wrapping virtually every single declaration made in mixin() and declaring everything as strings is even more nasty, and the contrast between mixin() declarations and 'normal' declarations looks completely stupid. (Totally unreadable + difficult to understand, breaks intellisense, code completion, syntax hilighting, etc... ie, unusable) Does anyone have a *realistic* suggestion for emulating custom attributes? Something that doesn't have any(/many) of the side effects I mention? I haven't come up with anything that's acceptable yet. If not, I assert that D absolutely needs a custom attribute system. For us here, this will enable D the single biggest advantage over using C++ in the same context that I've identified so far. D's meta-programming is amazing, but sadly, proving pointless to me right now without being able to mark stuff appropriately. All the meta magic is hovering just out of my grasp, due to the fact I have no way to indicate what items should involve with what systems. Currently, I have to maintain big registry tables of junk that must be amended/updated any time anyone adds/changes anything... and I'm feeling rather embarrassed when I tell the other non-D programmers that they just need to update this table here... and here... and make sure that's in sync too before their stuff will just 'magically' work ;) patterns, I don't think there should be any mystery over how they should be implemented.
Apr 05 2012
charset="UTF-8" Content-Transfer-Encoding: quoted-printable Manu, as a workaround would marker interfaces help to solve your problem for = the time being? This is just a suggestion for the time being, as I agree with you, = attributes/annotations are quite handy. -- Paulo "Manu" <turkeyman gmail.com> wrote in message = news:mailman.1363.1333627256.4860.digitalmars-d puremagic.com... I just want to add more real-world experience to the controversy. I'm finding myself needing to use custom attributes almost every day.=20 I have numerous systems that need to scan the module for things marked = accordingly to automate bindings to their respective systems. This is my current list of attributes I want to mark things with: Export to game engine Export to script language Import from game engine ** Import from script language (tentative, I'm sure I'll need it in a = few more days) Expose to editor (with additional properties; description, edit type, = etc) Serialise (load/save game) Replay serialisation (a different kind of serialisation that works = with different data sets) And others I've encountered in passing that I can't recall right now. As you can imagine, any attempt to 'work around' the lack of an = attribute system, ie, (ab)using enums, etc as have been suggested, leads = to a big mess in the context of all these requirements. Management of such lists of stuff in disconnected places in code is time = consuming, thoroughly annoying, error-prone, difficult to maintain, and = leaves programmers with the bitter taste of C++. Alternatively, wrapping virtually every single declaration made in = mixin() and declaring everything as strings is even more nasty, and the = contrast between mixin() declarations and 'normal' declarations looks = completely stupid. (Totally unreadable + difficult to understand, breaks = intellisense, code completion, syntax hilighting, etc... ie, unusable) Does anyone have a *realistic* suggestion for emulating custom = attributes? Something that doesn't have any(/many) of the side effects I = mention? I haven't come up with anything that's acceptable yet. If not, I assert that D absolutely needs a custom attribute system. For = us here, this will enable D the single biggest advantage over using C++ = in the same context that I've identified so far. D's meta-programming is amazing, but sadly, proving pointless to me = right now without being able to mark stuff appropriately. All the meta = magic is hovering just out of my grasp, due to the fact I have no way to = indicate what items should involve with what systems. Currently, I have to maintain big registry tables of junk that must be = amended/updated any time anyone adds/changes anything... and I'm feeling = rather embarrassed when I tell the other non-D programmers that they = just need to update this table here... and here... and make sure that's = in sync too before their stuff will just 'magically' work ;) patterns, I don't think there should be any mystery over how they should = be implemented.
Apr 05 2012
On 5 April 2012 15:04, Paulo Pinto <pjmlp progtools.org> wrote:as a workaround would marker interfaces help to solve your problem for the time being?I don't think it'd suit my purposes implemented as an interface for a variety of reasons: I need to be able to attribute many different types of things; data members, static functions, methods, etc. I need to be able to annotate 'loose' things at module scope. The whole point of the system is that it doesn't enforce a rigid interface. From my examples above, these items could be basically anything, anywhere.
Apr 05 2012
Paulo Pinto:design patterns, I don't think there should be any mystery over how they should be implemented.There are other interesting ways to conceive attributes. I think of them in a different way, more like user-defined ways to extend the static type system. Bye, bearophile
Apr 05 2012
On 4/5/2012 5:00 AM, Manu wrote:I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
Le 05/04/2012 19:35, Walter Bright a écrit :On 4/5/2012 5:00 AM, Manu wrote:They should be attached to declarations.patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On 4/5/12 12:44 PM, deadalnix wrote:Le 05/04/2012 19:35, Walter Bright a écrit :The question was whether the declaration affects the type of the declared or not. AndreiOn 4/5/2012 5:00 AM, Manu wrote:They should be attached to declarations.patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On Thu, 05 Apr 2012 14:05:49 -0400, Andrei Alexandrescu = <SeeWebsiteForEmail erdani.org> wrote:On 4/5/12 12:44 PM, deadalnix wrote:nLe 05/04/2012 19:35, Walter Bright a =C3=A9crit :On 4/5/2012 5:00 AM, Manu wrote:topatterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk=aremany smart people about attributes. But I did find some confusion - =orthey best attached to the variable/function (i.e. "storage class"), =attached to the type ("type constructor")? I think the former. =rAttaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable o=The question was whether the declaration affects the type of the =function is an apropos solution.They should be attached to declarations.declared or not.For user-defined attributes, no. This is metadata for the programmer/li= b = to decode. Obviously, compiler-defined attributes can. -Steve
Apr 05 2012
On 04/05/2012 08:05 PM, Andrei Alexandrescu wrote:On 4/5/12 12:44 PM, deadalnix wrote:Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.Le 05/04/2012 19:35, Walter Bright a écrit :The question was whether the declaration affects the type of the declared or not. AndreiOn 4/5/2012 5:00 AM, Manu wrote:They should be attached to declarations.patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On 4/5/2012 11:32 AM, Timon Gehr wrote:Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.Having it perturb the type implies a huge swamp of how that affects the semantics. You've got overloading, name mangling, type inference, implicit conversions, covariance, etc. All I can say is I see no way that can work with user defined semantics.
Apr 05 2012
Le 05/04/2012 20:51, Walter Bright a écrit :On 4/5/2012 11:32 AM, Timon Gehr wrote:I did some hacking into dmd in that regard, and I can confirm this is pretty hard. The problem is already quite hard, but the lack of separation of concerns into dmd's ast make things even harder. I'm afraid we have to delay anything that do codeception in a first shot, which is really sad because this is promising. I still think this is somewhere we have to go at some point, but we will have to wait.Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.Having it perturb the type implies a huge swamp of how that affects the semantics. You've got overloading, name mangling, type inference, implicit conversions, covariance, etc. All I can say is I see no way that can work with user defined semantics.
Apr 05 2012
On 5 April 2012 21:32, Timon Gehr <timon.gehr gmx.ch> wrote:On 04/05/2012 08:05 PM, Andrei Alexandrescu wrote:oOn 4/5/12 12:44 PM, deadalnix wrote:Le 05/04/2012 19:35, Walter Bright a =C3=A9crit :On 4/5/2012 5:00 AM, Manu wrote:patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk t=emany smart people about attributes. But I did find some confusion - ar=ngthey best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attachi=Didn't someone already say there were existing language defined attributes that could be neatly implemented via libs if the feature were available? Which ones were they?Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.The question was whether the declaration affects the type of the declared or not. Andreiit to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.They should be attached to declarations.
Apr 06 2012
On 2012-04-05 19:35, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote:specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this. -- /Jacob Carlborgpatterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On 05-04-2012 22:06, Jacob Carlborg wrote:On 2012-04-05 19:35, Walter Bright wrote:attached to. How feasible this is with D's rather... loose attribute/modifier parsing, I don't know. -- - AlexOn 4/5/2012 5:00 AM, Manu wrote:specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this.patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
Le 05/04/2012 22:06, Jacob Carlborg a écrit :On 2012-04-05 19:35, Walter Bright wrote:This is bar's declaration.On 4/5/2012 5:00 AM, Manu wrote:specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this.patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On Thursday, 5 April 2012 at 17:36:31 UTC, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote:I'm not sure if I'm understanding this correctly, but by attaching to the type do you mean altering the type of the declaration such as shared or const do? If so, I am completely against attributes being able to do this; there's already better ways such as a struct with alias this. Another issue is that if runtime reflection gets added, it would be nice to be able to add attributes at runtime. This could cause things to break if the type itself is changed instead of getting attached to the declaration. Plus, attributes should not be invasive, they're just notes. The two main situations where I see attributes being used are: 1) Add some information about a declaration, such as NotSerialized on a field. 2) Add some information to a type, such as Serializable. If this can be done, with being able to pass compile-time value(s) to the attribute, all situations I have ever desired/seen/used attributes for would work nicely.design patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
On 4/6/12 1:35 AM, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote:I don't understand the difference between "storage class" and "type constructor". I guess I do. But my answer is the same as deadalnix: they are attached to declarations (at compile time). Can you give us an example of the confusion that arose? I can't understand it without examples. I think it should work like this: custom class Foo { custom void bar() { } void baz() { } } class Other {} __traits(hasAttribute, Foo, 'custom') --> true __traits(hasAttribute, Other, 'custom') --> false // I have no idea how to iterate the members of Foo, or get a reference to the "bar" method... I can't understand what __traits(getMember) returns from the docs...patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues.
Apr 05 2012
On 2012-04-06 05:30, Ary Manzana wrote:I don't understand the difference between "storage class" and "type constructor". I guess I do. But my answer is the same as deadalnix: they are attached to declarations (at compile time). Can you give us an example of the confusion that arose? I can't understand it without examples. I think it should work like this: custom class Foo { custom void bar() { } void baz() { } } class Other {} __traits(hasAttribute, Foo, 'custom') --> true __traits(hasAttribute, Other, 'custom') --> false // I have no idea how to iterate the members of Foo, or get a reference to the "bar" method... I can't understand what __traits(getMember) returns from the docs...I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a". -- /Jacob Carlborg
Apr 06 2012
On 04/06/2012 02:23 PM, Jacob Carlborg wrote:I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a".not_null cannot be attached to "Foo". It would have to create a new symbol not_null(Foo). And then, all the concerns Walter has raised apply.
Apr 06 2012
On 2012-04-06 14:31, Timon Gehr wrote:not_null cannot be attached to "Foo". It would have to create a new symbol not_null(Foo). And then, all the concerns Walter has raised apply.Hmm, I guess. But it would be nice to have :) -- /Jacob Carlborg
Apr 06 2012
Jacob Carlborg wrote:I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a".Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))
Apr 06 2012
On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:Jacob Carlborg wrote:There's no need to attribute a return value. A) I think you're confusing it with attributing *types* again, and B) you can just attribute the function its self, and have access to precisely the same information. You can't attribute a return value, since attributes aren't transferred along with assignments, they are bound to their respective declaration.I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a".Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))
Apr 06 2012
On 2012-04-06 14:55, Manu wrote:On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl <mailto:bncrbme jadamspam.pl>> wrote: Jacob Carlborg wrote: I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a". Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo")) There's no need to attribute a return value. A) I think you're confusing it with attributing *types* again, and B) you can just attribute the function its self, and have access to precisely the same information. You can't attribute a return value, since attributes aren't transferred along with assignments, they are bound to their respective declaration.It depends on what we want out of attributes. -- /Jacob Carlborg
Apr 06 2012
Manu wrote:On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo")) There's no need to attribute a return value. A) I think you're confusing it with attributing *types* again, and B) you can just attribute the function its self, and have access to precisely the same information. You can't attribute a return value, since attributes aren't transferred along with assignments, they are bound to their respective declaration.See http://msdn.microsoft.com/en-us/library/b3787ac0%28v=vs.80%29.aspx Attributes on return values are useful for RPC methods. For example: with attribute, one can specify how return value is serialized/marshalled. type _simultaneously_. I don't think we should limit D ones to functions and parameters.
Apr 06 2012
On 2012-04-06 14:38, Piotr Szturmaj wrote:Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))Hmm, or something like how Java does it. You attached this information when you declare the attribute: Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection. Target({ElementType.METHOD}) // This annotation can only be applied to class methods. public interface Tweezable { } Or with another syntax: attribute target(type) struct not_null {} -- /Jacob Carlborg
Apr 06 2012
Jacob Carlborg wrote:On 2012-04-06 14:38, Piotr Szturmaj wrote:I think that target is a solution for simple types, but UDTs may use another one: struct MyAttr { template Attach(Symbol) { static if (!is(typeof(Symbol) == class) || !is(typeof(Symbol) : A)) static assert(0, "MyAttr must be attached to classes derived from class A"); } } This allows more complex target checking possible. Besides above example, some attributes can be mutually exclusive and __traits(hasAttribute, ...) may be used to check that.Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))Hmm, or something like how Java does it. You attached this information when you declare the attribute: Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection. Target({ElementType.METHOD}) // This annotation can only be applied to class methods. public interface Tweezable { } Or with another syntax: attribute target(type) struct not_null {}
Apr 06 2012
Le 06/04/2012 14:23, Jacob Carlborg a écrit :On 2012-04-06 05:30, Ary Manzana wrote:As foo isn't a declaration, I don't think it is attribute we want here. Or an extension, because it have a lot of consequences.I don't understand the difference between "storage class" and "type constructor". I guess I do. But my answer is the same as deadalnix: they are attached to declarations (at compile time). Can you give us an example of the confusion that arose? I can't understand it without examples. I think it should work like this: custom class Foo { custom void bar() { } void baz() { } } class Other {} __traits(hasAttribute, Foo, 'custom') --> true __traits(hasAttribute, Other, 'custom') --> false // I have no idea how to iterate the members of Foo, or get a reference to the "bar" method... I can't understand what __traits(getMember) returns from the docs...I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a".
Apr 06 2012
On 5 April 2012 20:35, Walter Bright <newshound2 digitalmars.com> wrote:On 4/5/2012 5:00 AM, Manu wrote:Yes, most certainly the former. The latter is already possible with tricks (a trivial template for instance). An attribute/annotation should associate with select instances/declarations of things. I don't think it should affect the type, although this shows a conceptual problem when referring to existing attributes via the same terminology. Obviously one might consider 'const', 'pure', etc attributes themselves, and they clearly do affect the type. Perhaps that's the key distinction between an ' ' attribute(/'annotation'?), and a no-' ' attribute?patterns, I don't think there should be any mystery over how they should be implemented.At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 06 2012
On 04/06/2012 11:57 AM, Manu wrote:I don't think it should affect the type, although this shows a conceptual problem when referring to existing attributes via the same terminology. Obviously one might consider 'const', 'pure', etc attributes themselves, and they clearly do affect the type. Perhaps that's the key distinction between an ' ' attribute(/'annotation'?), and a no-' ' attribute?safe affects the type.
Apr 06 2012
On 6 April 2012 13:06, Timon Gehr <timon.gehr gmx.ch> wrote:On 04/06/2012 11:57 AM, Manu wrote:I realise that, I'm just suggesting this is a possible solution to the confusion... if the distinction were to be made clearly. I guess it's impossible though, can't go claiming 'safe' from the global namespace :)I don't think it should affect the type, although this shows a conceptual problem when referring to existing attributes via the same terminology. Obviously one might consider 'const', 'pure', etc attributes themselves, and they clearly do affect the type. Perhaps that's the key distinction between an ' ' attribute(/'annotation'?), and a no-' ' attribute?safe affects the type.
Apr 06 2012
On 2012-04-05 14:00, Manu wrote:I just want to add more real-world experience to the controversy. I'm finding myself needing to use custom attributes almost every day. I have numerous systems that need to scan the module for things marked accordingly to automate bindings to their respective systems.Yes, give us custom attributes now :) -- /Jacob Carlborg
Apr 05 2012
On 4/6/2012 4:43 AM, Jacob Carlborg wrote:On 2012-04-05 14:00, Manu wrote:Pretty please.I just want to add more real-world experience to the controversy. I'm finding myself needing to use custom attributes almost every day. I have numerous systems that need to scan the module for things marked accordingly to automate bindings to their respective systems.Yes, give us custom attributes now :)
Apr 05 2012
On 4/5/2012 5:00 AM, Manu wrote:I don't think there should be any mystery over how they should be implemented.I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 05 2012
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote:I like it for the most part. One thing I'd like to see is placing multiple attributes both by using multiple attr()'s, and by using comma separated identifier/expression pairs inside a single attr. In other words, the following two declarations would be identical. attr(Description = "Blah", ReadOnly) int ID; attr(Description = "Blah") attr(ReadOnly) int ID; My only concerns: First, attr() is a little verbose / not exactly pretty. This isn't really a big issue, since attributes aren't exactly piled on and it makes it easy to tell what's going on. It is a little uglier than in other languages however. Secondly, from what I can tell it's an arbitrary key value combo. What would happen if you're working on a larger project and two unrelated libraries try to use the same attribute name to mean different things? With the module system this issue doesn't exist since you have to import it and can selectively/privately do so, but from what I understand the method you're proposing doesn't declare the attribute itself at all. Am I just misunderstanding this part?design patterns, Idon't think there should be any mystery over how they shouldbe implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 06 2012
On 4/6/2012 12:17 AM, Kapps wrote:I like it for the most part. One thing I'd like to see is placing multiple attributes both by using multiple attr()'s, and by using comma separated identifier/expression pairs inside a single attr. In other words, the following two declarations would be identical. attr(Description = "Blah", ReadOnly) int ID; attr(Description = "Blah") attr(ReadOnly) int ID;Yes, that makes sense.My only concerns: First, attr() is a little verbose / not exactly pretty. This isn't really a big issue, since attributes aren't exactly piled on and it makes it easy to tell what's going on. It is a little uglier than in other languages however.Could do: [[name = value]] I suppose. Not sure what's better.Secondly, from what I can tell it's an arbitrary key value combo. What would happen if you're working on a larger project and two unrelated libraries try to use the same attribute name to mean different things? With the module system this issue doesn't exist since you have to import it and can selectively/privately do so, but from what I understand the method you're proposing doesn't declare the attribute itself at all. Am I just misunderstanding this part?Good question. I don't have experience using attributes, so I don't know if this would be a problem. Keep in mind that the attribute lookup will only be done for a particular symbol, there won't be any global lookup.
Apr 06 2012
On 06-04-2012 09:32, Walter Bright wrote:On 4/6/2012 12:17 AM, Kapps wrote:It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem. -- - AlexI like it for the most part. One thing I'd like to see is placing multiple attributes both by using multiple attr()'s, and by using comma separated identifier/expression pairs inside a single attr. In other words, the following two declarations would be identical. attr(Description = "Blah", ReadOnly) int ID; attr(Description = "Blah") attr(ReadOnly) int ID;Yes, that makes sense.My only concerns: First, attr() is a little verbose / not exactly pretty. This isn't really a big issue, since attributes aren't exactly piled on and it makes it easy to tell what's going on. It is a little uglier than in other languages however.Could do: [[name = value]] I suppose. Not sure what's better.Secondly, from what I can tell it's an arbitrary key value combo. What would happen if you're working on a larger project and two unrelated libraries try to use the same attribute name to mean different things? With the module system this issue doesn't exist since you have to import it and can selectively/privately do so, but from what I understand the method you're proposing doesn't declare the attribute itself at all. Am I just misunderstanding this part?Good question. I don't have experience using attributes, so I don't know if this would be a problem. Keep in mind that the attribute lookup will only be done for a particular symbol, there won't be any global lookup.
Apr 06 2012
On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
Am Fri, 06 Apr 2012 00:48:34 -0700 schrieb Walter Bright <newshound2 digitalmars.com>:On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name =3D name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init=20 */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors =3D __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors =3D ..." should be usable here too.It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.=20 =20 Perhaps a better scheme is: =20 enum foo =3D 3; =20 ... =20 attr(foo) int x; =20 That way, foo will follow all the usual rules. =20
Apr 06 2012
On 4/6/2012 2:41 AM, Johannes Pfau wrote:implementation?
Apr 06 2012
Am Fri, 06 Apr 2012 03:06:51 -0700 schrieb Walter Bright <newshound2 digitalmars.com>:On 4/6/2012 2:41 AM, Johannes Pfau wrote:OK, but my post was only about the syntax, there's no runtime/compile time specific part in it (the struct's constructor has to be called using CTFE instead of at runtime, but that's the only difference I see)implementation?
Apr 06 2012
On 4/6/12 5:06 AM, Walter Bright wrote:On 4/6/2012 2:41 AM, Johannes Pfau wrote:Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate. Andreiimplementation?
Apr 06 2012
Le 06/04/2012 17:00, Andrei Alexandrescu a écrit :On 4/6/12 5:06 AM, Walter Bright wrote:Again, I rise the need of AOP. No need for runtime attribute or compiler magic if we have AOP that could interleave « clunky D code you wouldn't want to write by hand » without adding yet again another language feature.On 4/6/2012 2:41 AM, Johannes Pfau wrote:Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate. Andreiimplementation?
Apr 06 2012
On 04/06/2012 05:00 PM, Andrei Alexandrescu wrote:On 4/6/12 5:06 AM, Walter Bright wrote:What would that look like?On 4/6/2012 2:41 AM, Johannes Pfau wrote:Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand).implementation?Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs.What do you have in mind here? All lowerings I am aware of are trivial ones and their implementation resulted in sloppy error handling (eg: foreach) for no clear benefit. Some of them (eg: with statement) have even made the implementation bug situation worse.We should use them wherever appropriate. AndreiI don't think they are in this case. What will help reducing implementation bugs is that most of their implementation is already covered by the CTFE implementation.
Apr 06 2012
On 4/6/12 10:09 AM, Timon Gehr wrote:Essentially we want to associate with any symbol (be it a type, function, method, or whatnot) some extra information in the form of a tuple of key/value pairs. The value can be anything CTFE. How would one do that "by hand", albeit ugly and verbose? Once we get the desired functionality, we work back on a syntax for it. And we're done.Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand).What would that look like?All: foreach, scope, operator overloading - wherever we used lowerings it's been an unqualified success. I am only sorry we didn't use them more often and more systematically.Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs.What do you have in mind here?All lowerings I am aware of are trivial ones and their implementation resulted in sloppy error handling (eg: foreach) for no clear benefit.Defining foreach as a lowering clarifies to both the library author and the user what the expectations are.Some of them (eg: with statement) have even made the implementation bug situation worse."with" is not implemented via a lowering. Andrei
Apr 06 2012
On 04/06/2012 09:15 PM, Andrei Alexandrescu wrote:On 4/6/12 10:09 AM, Timon Gehr wrote:There is no existing in-language solution whose only bad property is its ugliness, because it cannot be allowed to introduce additional symbols.Essentially we want to associate with any symbol (be it a type, function, method, or whatnot) some extra information in the form of a tuple of key/value pairs. The value can be anything CTFE. How would one do that "by hand", albeit ugly and verbose? Once we get the desired functionality, we work back on a syntax for it. And we're done.Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand).What would that look like?I think they have been applied where they were appropriate. What other existing language features would you rather have specified as a lowering?All: foreach, scope, operator overloading - wherever we used lowerings it's been an unqualified success. I am only sorry we didn't use them more often and more systematically.Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs.What do you have in mind here?Agreed, using lowering custom overloading of language constructs is good. These usages have slipped my mind because they are so different from what we are discussing here. I was thinking about foreach over built in arrays. For example: foreach(double i,x; (int[]).init){} Error: cannot implicitly convert expression (i) of type double to ulong i.e. using lowering for implementation without any additional checks is not a good thing. Anyway, how does the argument apply to the custom attribute case? The specification of how custom attributes work is certainly simpler and more clear than the specification of how the 'code that is too ugly to be written by hand' is generated and getting it right should be comparably difficult for both. The solution that uses a lowering would need additional compiler support for hiding additionally generated symbols. This makes the lowering even harder to follow for someone who wants to get started on custom attributes. It just seems kludgy to me.All lowerings I am aware of are trivial ones and their implementation resulted in sloppy error handling (eg: foreach) for no clear benefit.Defining foreach as a lowering clarifies to both the library author and the user what the expectations are.
Apr 06 2012
On 4/6/12 2:47 PM, Timon Gehr wrote:There is no existing in-language solution whose only bad property is its ugliness, because it cannot be allowed to introduce additional symbols.You can always assume fresh variables even though indeed there's no support for them. Just use __ as prefix and then combine with a cookie and the existing symbol name. There will be no clashes.I forgot the new lambda syntax ("=>") was defined as a lowering and as a consequence is came virtually bug free.All: foreach, scope, operator overloading - wherever we used lowerings it's been an unqualified success. I am only sorry we didn't use them more often and more systematically.I think they have been applied where they were appropriate. What other existing language features would you rather have specified as a lowering?Some array and associative array literals and operations. All object copying.Anyway, how does the argument apply to the custom attribute case? The specification of how custom attributes work is certainly simpler and more clear than the specification of how the 'code that is too ugly to be written by hand' is generated and getting it right should be comparably difficult for both. The solution that uses a lowering would need additional compiler support for hiding additionally generated symbols. This makes the lowering even harder to follow for someone who wants to get started on custom attributes. It just seems kludgy to me.Expressing attributes in terms of what they do within attribute-less D is crucial to keeping both definition and implementation simple. Hidden symbols are a non-issue. Andrei
Apr 06 2012
On Fri, 06 Apr 2012 11:00:25 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 4/6/12 5:06 AM, Walter Bright wrote:I don't think that applies here. We have no low-level mechanism to affect the compiler internals, which is where attribute metadata belongs. -SteveOn 4/6/2012 2:41 AM, Johannes Pfau wrote:Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate.implementation?
Apr 06 2012
On 6 April 2012 12:41, Johannes Pfau <nospam example.com> wrote:Am Fri, 06 Apr 2012 00:48:34 -0700 schrieb Walter Bright <newshound2 digitalmars.com>:+1On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name =3D name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors =3D __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors =3D ..." should be usable here too.It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 04/06/2012 11:41 AM, Johannes Pfau wrote:Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name = name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors = __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors = ..." should be usable here too.This all seems very reasonable. I think this is how things should work. (maybe syntax will need to be different, because Walter does not seem to like the idea of un-reserving identifier.)
Apr 06 2012
Le 06/04/2012 11:41, Johannes Pfau a écrit :Am Fri, 06 Apr 2012 00:48:34 -0700 schrieb Walter Bright<newshound2 digitalmars.com>:That is a really nice proposal !On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=vs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=vs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=vs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=vs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name = name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors = __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors = ..." should be usable here too.It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 6 April 2012 15:13, deadalnix <deadalnix gmail.com> wrote:Le 06/04/2012 11:41, Johannes Pfau a =C3=A9crit : Am Fri, 06 Apr 2012 00:48:34 -0700s.com>schrieb Walter Bright<newshound2 digitalmars.**com<newshound2 digitalmar=p://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx>:On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:implementation? http://msdn.microsoft.com/en-**US/library/48zeb25s(v=3Dvs.80).**aspx<htt=It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.tp://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx>http://msdn.microsoft.com/en-**US/library/sw480ze8(v=3Dvs.100).**aspx<ht=p://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx>http://msdn.microsoft.com/en-**US/library/z919e8tw(v=3Dvs.80).**aspx<htt=p://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx>"disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-**US/library/b3787ac0(v=3Dvs.80).**aspx<htt=This is precisely how I have always imagined the system working. Walter: can you comment why you think this is not do-able, or not a good way to go about it?Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name =3D name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors =3D __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors =3D ..." should be usable here too.That is a really nice proposal !
Apr 06 2012
On 4/6/12 3:48 PM, Walter Bright wrote:On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:At least in .Net and Java it's something like this. 1. You declare your attributes. This is something good, because you have a place to say "This attribute is used for marking fields as non-serializable". The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; } 2. You use them by using their names. What you are proposing if for attribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy. --- Now, your proposal is much simpler and it will become inconvenient in some cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x; /// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process. Now, to implement this is not very much difficult than what you proposed. 1. Introduce the syntax to define attributes. Piece of cake, since it's much more or less the syntax of a struct, but functions or nested types are not allowed. Parse them into an AttributeDecl or something like that. 2. When the compiler finds attr(field = value) it uses normal lookup rules to find "attr". Then it checks it's an attributes. Then all fields are check in turn to see if their type match. You can probably put there anything that's compile-time evaluatable, though usually primitive types and strings are enough. If a field is not specified, it's type.init will be used. 3. The syntax for querying is almost the same as you proposed: __traits(hasAttribute, x, serializable) // true __traits(getAttribtue, x, serializable, name) // "Foo" 4. Declare the core attributes in object.di or similar: safe, nothrow, etc. You can also document them. 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute can be used for that.It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 4/6/2012 2:50 AM, Ary Manzana wrote:The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; }I don't see the need for creating a new kind of symbol.2. You use them by using their names. What you are proposing if for attribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy.This is a runtime system.Now, your proposal is much simpler and it will become inconvenient in some cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x;No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax./// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process.I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.Now, to implement this is not very much difficult than what you proposed. 1. Introduce the syntax to define attributes. Piece of cake, since it's much more or less the syntax of a struct, but functions or nested types are not allowed. Parse them into an AttributeDecl or something like that. 2. When the compiler finds attr(field = value) it uses normal lookup rules to find "attr". Then it checks it's an attributes. Then all fields are check in turn to see if their type match. You can probably put there anything that's compile-time evaluatable, though usually primitive types and strings are enough. If a field is not specified, it's type.init will be used. 3. The syntax for querying is almost the same as you proposed: __traits(hasAttribute, x, serializable) // true __traits(getAttribtue, x, serializable, name) // "Foo" 4. Declare the core attributes in object.di or similar: safe, nothrow, etc. You can also document them. 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute can be used for that.safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.
Apr 06 2012
On 4/6/12 6:12 PM, Walter Bright wrote:On 4/6/2012 2:50 AM, Ary Manzana wrote:Yes, but I'm thinking about a compile-time system (as I showed in the example usages below).The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; }I don't see the need for creating a new kind of symbol.2. You use them by using their names. What you are proposing if for attribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy.This is a runtime system.Hmmm... I didn't get that quite well. You are using the symbol's name as the attribute name? In my example I missed splitting it into two files: my_attributes.d: attribute serialize { } my_usage_of_it.d: import my_attributes; serialize(...)Now, your proposal is much simpler and it will become inconvenient in some cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x;No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax.pretending to be an interface and has semantic support in the compiler./// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process.I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.Now, to implement this is not very much difficult than what you proposed. 1. Introduce the syntax to define attributes. Piece of cake, since it's much more or less the syntax of a struct, but functions or nested types are not allowed. Parse them into an AttributeDecl or something like that. 2. When the compiler finds attr(field = value) it uses normal lookup rules to find "attr". Then it checks it's an attributes. Then all fields are check in turn to see if their type match. You can probably put there anything that's compile-time evaluatable, though usually primitive types and strings are enough. If a field is not specified, it's type.init will be used. 3. The syntax for querying is almost the same as you proposed: __traits(hasAttribute, x, serializable) // true __traits(getAttribtue, x, serializable, name) // "Foo" 4. Declare the core attributes in object.di or similar: safe, nothrow, etc. You can also document them. 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute can be used for that.safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.
Apr 06 2012
On 4/6/2012 3:27 AM, Ary Manzana wrote:All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.pretending to be an interface and has semantic support in the compiler.
Apr 06 2012
On 04/06/2012 12:53 PM, Walter Bright wrote:On 4/6/2012 3:27 AM, Ary Manzana wrote:The proposal is not to make the semantics of safe user defined. I think he proposes to make 'safe' a symbol that is looked up like an user defined symbol. Some languages do the same for the built-in integer type.All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.pretending to be an interface and has semantic support in the compiler.
Apr 06 2012
On 4/6/12 7:09 PM, Timon Gehr wrote:On 04/06/2012 12:53 PM, Walter Bright wrote:The compiler does the same for TypeInfo, TypeInfo_ClassDeclaration or what ever, Object, etc. I'm just proposing safe to be seen as a user-defined attribute, but implemented in the compiler with special semantic. I'm saying it so that lookup rules become easier: just search. No special cases like "if the attribute name is safe". Of course, treat the special cases later inside the compiler code.On 4/6/2012 3:27 AM, Ary Manzana wrote:The proposal is not to make the semantics of safe user defined. I think he proposes to make 'safe' a symbol that is looked up like an user defined symbol. Some languages do the same for the built-in integer type.All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.pretending to be an interface and has semantic support in the compiler.
Apr 06 2012
On 04/06/2012 12:12 PM, Walter Bright wrote:On 4/6/2012 2:50 AM, Ary Manzana wrote:It would behave like a struct anyway. The issue is whether any struct should be allowed to be used as an attribute, or whether a runtime instance of an attribute can be created. Syntax could just as well be this: attribute struct Foo { // ... }The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; }I don't see the need for creating a new kind of symbol.In Java, yes. But the general scheme works well even at compile time. It is possible to evaluate struct constructors at compile time. enum Foo attr = __traits(getAttribute, func, Foo);2. You use them by using their names. What you are proposing if for attribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy.This is a runtime system.I don't see how that would work. Do you propose to define attributes based on the mapping of the name of random manifest constants to their value? That would be a kludgy hack.Now, your proposal is much simpler and it will become inconvenient in some cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x;No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x;There would be no initialization in the attr syntax.I think it is cleaner on a conceptual level, even if the syntax was attr(serialize("Foo"))/// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process.I don't see that it is cleaner- there's no particular reason why a new symbol type needs to be introduced.There is not strictly a need for a _new_ symbol type, but attribute lookup should definitely be symbol based and not string/value based. Why would there be any benefit in bypassing the module system for user defined attributes?
Apr 06 2012
On 4/6/12 6:29 PM, Timon Gehr wrote:On 04/06/2012 12:12 PM, Walter Bright wrote:True, I struct can be fine. And I don't see any problem in using it in runtime. Though I'm sure nobody would like it to remain in the obj file if it's only used at compile time...On 4/6/2012 2:50 AM, Ary Manzana wrote:It would behave like a struct anyway. The issue is whether any struct should be allowed to be used as an attribute, or whether a runtime instance of an attribute can be created. Syntax could just as well be this: attribute struct Foo { // ... }The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; }I don't see the need for creating a new kind of symbol.
Apr 06 2012
On 6 April 2012 13:12, Walter Bright <newshound2 digitalmars.com> wrote:On 4/6/2012 2:50 AM, Ary Manzana wrote:I don't think it's necessary to declare the struct as attribute explicitly, the ' ' can easily imply the usage all on its own in the declaration. The struct would remain a perfectly normal struct, and will be useful if you want to get a struct somewhere in the code to inspect details about the attribute. SomeStruct(blah) int x; .. SomeStruct s = __traits(getAttribute, SomeStruct, x); ... do some stuff with the information that x was attributed static if(s.thing == ??)The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; }I don't see the need for creating a new kind of symbol.2. You use them by using their names. What you are proposing if forIt doesn't need to be runtime. The syntax works perfectly at compile time? Now, your proposal is much simpler and it will become inconvenient in someattribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy.This is a runtime system.Please don't. We've gone from a minor case of bracket spam now to a whole bunch of extra lines for every single member, and you've also removed the tight syntactical connection of the values from their attribute declaration (one of the most important details, its safety, when people update/edit classes). This is fast approaching the disconnected enum table which is the whole thing we're trying to avoid. There's also a namespace/scope problem here. 2 different systems from 2 different libraries will almost certainly use the 'serialise' attribute.cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x;No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax.See my point above, I don't think there's any need for a new symbol type... The compiler would just keep a little table of attributes alongside declarations, which you can query if you want to./// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process.I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.
Apr 06 2012
On 2012-04-06 12:12, Walter Bright wrote:I don't see the need for creating a new kind of symbol.If you create a new symbol, i.e. "Foo" then it would obey the normal look up rules.This is a runtime system.Says who? It doesn't need to be in D.I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.For attributes with a single value this syntax sugar can be allowed (and is in Java): serialize("Foo") int x; I think that is clean. -- /Jacob Carlborg
Apr 06 2012
On 2012-04-06 11:50, Ary Manzana wrote:On 4/6/12 3:48 PM, Walter Bright wrote:This is much better, as I've said before. -- /Jacob CarlborgOn 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:At least in .Net and Java it's something like this. 1. You declare your attributes. This is something good, because you have a place to say "This attribute is used for marking fields as non-serializable".It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 6 April 2012 10:48, Walter Bright <newshound2 digitalmars.com> wrote:On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:What about: struct editor { this(string name, EditType, Colour =3D Colour.Default, string description= =3D null) { //... } blah blah blah } attr(editor("thing",...blah...)) I don't see the advantage over: editor(...) ?It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 4/6/2012 3:23 AM, Manu wrote:What about: struct editor { this(string name, EditType, Colour = Colour.Default, string description = null) { //... } blah blah blah } attr(editor("thing",...blah...))Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?I don't see the advantage over: editor(...) ?Name collisions with other attributes.
Apr 06 2012
On 04/06/2012 12:28 PM, Walter Bright wrote:On 4/6/2012 3:23 AM, Manu wrote:Yes, allowing the arguments to be different is a crucial feature. Custom attributes are not a boolean thing, that is just the case for built-in ones. They are arbitrary data that is attached to a declaration and can then be used to build powerful semantics using compile time reflection.What about: struct editor { this(string name, EditType, Colour = Colour.Default, string description = null) { //... } blah blah blah } attr(editor("thing",...blah...))Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more. Maybe we could just keep all the lower case attributes reserved in order to be future proof.I don't see the advantage over: editor(...) ?Name collisions with other attributes.
Apr 06 2012
Am Fri, 06 Apr 2012 12:43:27 +0200 schrieb Timon Gehr <timon.gehr gmx.ch>:On 04/06/2012 12:28 PM, Walter Bright wrote:Or add a reserved pseudo-namespace (like e.g 'builtin') for compiler defined attributes and use normal namespace resolution for those: safe <=> builtin.safeOn 4/6/2012 3:23 AM, Manu wrote:Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more. Maybe we could just keep all the lower case attributes reserved in order to be future proof.I don't see the advantage over: editor(...) ?Name collisions with other attributes.
Apr 06 2012
Walter Bright wrote:Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?The former.The same applies to other identifiers, like class named "class". NET has predefined attributes too, but they use the same syntax as the custom ones: [MyAttr(5)] int x; I think MyAttr(5) declaration looks more readable than attr(MyAttr(5)). To avoid name clashes, in case of using builtin name, qualified identifier should be used: myModule.pure pure void fn() {}I don't see the advantage over: editor(...) ?Name collisions with other attributes.
Apr 06 2012
Piotr Szturmaj wrote:myModule.pure pure void fn() {}should be: myModule.safe safe void fn() {}
Apr 06 2012
On 6 April 2012 13:28, Walter Bright <newshound2 digitalmars.com> wrote:On 4/6/2012 3:23 AM, Manu wrote:Of course, what's the point otherwise? This is the very definition of annotation. Everything needs to be exposed in the editor differently. The power of attributes are that they are tightly syntactically bound to the items they attribute. Nobody can change any class/struct without having the syntax force them to make any necessary corrections to their attributes too. I don't see the advantage over:What about: struct editor { this(string name, EditType, Colour = Colour.Default, string description = null) { //... } blah blah blah } attr(editor("thing",...blah..**.))Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?If they were declared as normal structs, they would follow normal namespace rules. company.lib.MyAttribute(...) should also be a valid expression. The only collisions are trusted, safe... I think programmers can handle a few reserved keywords. I already can't go and name a variable whatever I want for the same reason: int private = 10;editor(...) ?Name collisions with other attributes.
Apr 06 2012
On 2012-04-06 12:28, Walter Bright wrote:Name collisions with other attributes.Just as we have today with keywords and symbols, I don't see the problem. -- /Jacob Carlborg
Apr 06 2012
On Friday, 6 April 2012 at 12:52:27 UTC, Jacob Carlborg wrote:Just as we have today with keywords and symbols, I don't see the problem.Things like safe aren't keywords though. They are just magic identifiers. Think of the implementation: switch(tok.ident) { case Id::safe: case Id::property: // etc for built ins default: // handle user ones here } If you were to define a struct safe {}, which is perfectly legal D, and try to use it, you won't get what you expect. It will trigger the case safe before it goes to the default. So, the user defined one will just be quietly hidden.
Apr 06 2012
On 2012-04-06 15:48, Adam D. Ruppe wrote:On Friday, 6 April 2012 at 12:52:27 UTC, Jacob Carlborg wrote:I mean that "int" is a keyword and "int" is in the same "scope" as the rest of the symbols. So if we allow custom attributes, like " foo", it's the same "problem" as with regular identifiers. Regular identifiers can conflict with keywords. -- /Jacob CarlborgJust as we have today with keywords and symbols, I don't see the problem.Things like safe aren't keywords though. They are just magic identifiers. Think of the implementation: switch(tok.ident) { case Id::safe: case Id::property: // etc for built ins default: // handle user ones here } If you were to define a struct safe {}, which is perfectly legal D, and try to use it, you won't get what you expect. It will trigger the case safe before it goes to the default. So, the user defined one will just be quietly hidden.
Apr 07 2012
Le 06/04/2012 12:28, Walter Bright a écrit :On 4/6/2012 3:23 AM, Manu wrote:That isn't a good argument IMO. We have type int and user defined types. I cannot do struct int {}. Same for safe or property or any other language defined property.What about: struct editor { this(string name, EditType, Colour = Colour.Default, string description = null) { //... } blah blah blah } attr(editor("thing",...blah...))Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?I don't see the advantage over: editor(...) ?Name collisions with other attributes.
Apr 06 2012
Le 06/04/2012 12:23, Manu a écrit :On 6 April 2012 10:48, Walter Bright <newshound2 digitalmars.com <mailto:newshound2 digitalmars.com>> wrote: On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote: It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem. Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules. What about: struct editor { this(string name, EditType, Colour = Colour.Default, string description = null) { //... } blah blah blah } attr(editor("thing",...blah...)) I don't see the advantage over: editor(...) ?+1 I see no additional benefit for this. D have very good lookup rules for looking symbols into modules, so let's use them.
Apr 06 2012
On 2012-04-06 09:48, Walter Bright wrote:On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:What would "3" do in this case? Be the value of the attribute? -- /Jacob CarlborgIt actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem.Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
On 2012-04-06 09:32, Walter Bright wrote:Could do: [[name = value]] I suppose. Not sure what's better.No. See my other reply. -- /Jacob Carlborg
Apr 06 2012
On 2012-04-06 09:17, Kapps wrote:Secondly, from what I can tell it's an arbitrary key value combo. What would happen if you're working on a larger project and two unrelated libraries try to use the same attribute name to mean different things? With the module system this issue doesn't exist since you have to import it and can selectively/privately do so, but from what I understand the method you're proposing doesn't declare the attribute itself at all. Am I just misunderstanding this part?The way I'm thinking of attributes is that they are declared, somehow, in a module. Since it's declared in a module it would have the same rules any other declared symbol, with the possibility to use a fully qualified name. -- /Jacob Carlborg
Apr 06 2012
On 06-04-2012 08:47, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote: patterns, I > don't think there should be any mystery over how they should be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;I think this is mostly reasonable. I assume that it would be possible to use the comma operator to attach multiple values to it? I.e.: attr(foo = bar, baz) int x; My only other concern is what Kapps pointed out about larger projects and overlapping attribute names. -- - Alex
Apr 06 2012
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote:I like it. Perhaps attr(bar) could be equivalent to attr(bar = true) so you don't get any weird failure state for __traits(getAttribute?design patterns, Idon't think there should be any mystery over how they shouldbe implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 06 2012
On 4/6/2012 12:31 AM, Bernard Helyer wrote:I like it. Perhaps attr(bar) could be equivalent to attr(bar = true) so you don't get any weird failure state for __traits(getAttribute?That's what the hasAttribute is for.
Apr 06 2012
On 06-04-2012 09:31, Bernard Helyer wrote:On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:While I understand the rationale, that seems a bit too "magic"... -- - AlexOn 4/5/2012 5:00 AM, Manu wrote:I like it. Perhaps attr(bar) could be equivalent to attr(bar = true) so you don't get any weird failure state for __traits(getAttribute?design patterns, Idon't think there should be any mystery over how they shouldbe implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 06 2012
On 06-04-2012 08:47, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote: patterns, I > don't think there should be any mystery over how they should be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;Also, by storage class do you mean it will work only on fields? Attributes are very useful on many different kinds of declarations, so if that's the case, I think that would be too limiting. -- - Alex
Apr 06 2012
On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:Also, by storage class do you mean it will work only on fields?No. Storage classes work on fields, functions, and variables.
Apr 06 2012
On 06-04-2012 09:47, Walter Bright wrote:On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse). -- - AlexAlso, by storage class do you mean it will work only on fields?No. Storage classes work on fields, functions, and variables.
Apr 06 2012
On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 06-04-2012 09:54, Walter Bright wrote:On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else. Does a design like that still give rise to the semantic issues you mentioned (it isn't clear what those are)? -- - AlexWhat about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 4/6/2012 1:15 AM, Alex Rønne Petersen wrote:On 06-04-2012 09:54, Walter Bright wrote:What would an annotation on a type mean if it does not affect the type? Would it just be baggage carried along? If so, how would that affect types inside of a template, where the type was passed as a type constructor? How would type inference work? Would an alias carry or drop the baggage? How would overloading work? How would covariance work? It's a maze of complex decisions.On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else.What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.Does a design like that still give rise to the semantic issues you mentioned (it isn't clear what those are)?Yes. (I know Java does this. But Java has a trivial type system compared with D. It doesn't even have type aliases. It doesn't have type constructors. Etc.)
Apr 06 2012
On 04/06/2012 12:16 PM, Walter Bright wrote:On 4/6/2012 1:15 AM, Alex Rønne Petersen wrote:I don't get that either, it has to affect the type. It does not have any effects on the semantics of instances on the type though. Name mangling can stay the same though.On 06-04-2012 09:54, Walter Bright wrote:What would an annotation on a type mean if it does not affect the type?On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else.What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.Would it just be baggage carried along?Yes.If so, how would that affect types inside of a template, where the type was passed as a type constructor?How do you pass a type as a type constructor?How would type inference work?Just as it does now.Would an alias carry or drop the baggage?Carry. An alias does not change the referenced symbol.How would overloading work? How would covariance work?As they do now. Custom attributes don't have semantic meaning recognised by the compiler. They are just data.It's a maze of complex decisions.I think you can add a list of annotations to the class in the AST that represents a declaration (the common superclass of all declarations) and everything will just work.I think there is some sort of communication problem, because the feature that is being requested is quite simple. It would probably be valuable if you could point out the issues you see in detail (using example code.)Does a design like that still give rise to the semantic issues you mentioned (it isn't clear what those are)?Yes. (I know Java does this. But Java has a trivial type system compared with D. It doesn't even have type aliases. It doesn't have type constructors. Etc.)
Apr 06 2012
On 6 April 2012 14:03, Timon Gehr <timon.gehr gmx.ch> wrote:It's a maze of complex decisions.Yeah, I always imagined it being about that simple too... are you able to proof the concept? (I know Java does this. But Java has a trivial type system compared withI think you can add a list of annotations to the class in the AST that represents a declaration (the common superclass of all declarations) and everything will just work.Indeed.D. It doesn't even have type aliases. It doesn't have type constructors. Etc.)I think there is some sort of communication problem, because the feature that is being requested is quite simple. It would probably be valuable if you could point out the issues you see in detail (using example code.)
Apr 06 2012
On 4/6/12 3:54 PM, Walter Bright wrote:On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What's the difference between "type constructor" and "storage class" beside the name?What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 4/6/2012 2:18 AM, Ary Manzana wrote:On 4/6/12 3:54 PM, Walter Bright wrote:static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What's the difference between "type constructor" and "storage class" beside the name?What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 04/06/2012 12:17 PM, Walter Bright wrote:On 4/6/2012 2:18 AM, Ary Manzana wrote:Still, the 'static' in static struct S{ // ... } Affects S. Correct?On 4/6/12 3:54 PM, Walter Bright wrote:static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What's the difference between "type constructor" and "storage class" beside the name?What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
Le 06/04/2012 12:17, Walter Bright a écrit :On 4/6/2012 2:18 AM, Ary Manzana wrote:Why can't attribute be attached on declaration ? By the way, this whole qualify the type or something is a big misfeature. annotation should be attached to the declared stuff. attr Bar foo() { return Bar(); } is qualifying « foo ». Qualifying bar make no sense whatsoever.On 4/6/12 3:54 PM, Walter Bright wrote:static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What's the difference between "type constructor" and "storage class" beside the name?What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 04/06/12 11:18, Ary Manzana wrote:On 4/6/12 3:54 PM, Walter Bright wrote:attr(deprecated) struct T { int blah; } // every instance of S now marked with it. struct S { int blah; } attr(deprecated) S si; // just si marked; think "static S si;" etc I actually don't like the proposed scheme - it's both way to verbose and not nearly sufficient. I have to leave soon and don't have the time to fully describe the problems, but just a few key points: - Both of the above should work; the "storage class" is the more important part. Wouldn't just having the type-attributes automatically propagate (as a default "storage class") to the instances, w/o affecting the type in any way, be enough? - If the above would work, then there has to be a way to remove an attribute from some instances. - Attributes needs to be declared in some way, otherwise a typo will go undetected and you may not notice it until it's too late. Think " attr(serialisable)" etc - Attributes need to be mergeable, ie you really don't want to mark a significant number of symbols as serializable, exported-to-X, exported-to-Y etc. Something like "alias attr("serializable", "export_X", "export_Y") new_attr"; attr(new_attr) int i;" might work. - At the very least "__traits(getAttribute, x, foo)" needs to be something like "__traits( attr, x, foo); even better would be "x. attr("foo");". - Should attributes be strings? That would avoid clashes with keywords. OTOH that would mean that attribute definitions needs to use different syntax than plain structs. Hmm, maybe that would be a good thing anyway. - Namespaces. There needs to be a system NS and a compiler-specific NS. So that you can do things like attr(__GNU, "flatten", "hot") instead of "pragma(GNU_attribute, flatten, hot)". - Null/empty attributes, ie "alias attr() new_attr;", should work; necessary eg when the compiler lacks support for certain features. There are probably many more issues, these are just the few obvious ones that immediately come to mind. arturOn 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:What's the difference between "type constructor" and "storage class" beside the name?What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 04/06/2012 09:54 AM, Walter Bright wrote:On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:I think what was discussed there is that attr(foo) int x; Wouldn't change the type of x. attr(foo) struct Foo{} Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
On 4/6/2012 2:54 AM, Timon Gehr wrote:Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not? Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not? And, whatever you choose for the semantics, what is the sensible, intuitive rule for it?
Apr 06 2012
On 04/06/2012 12:23 PM, Walter Bright wrote:On 4/6/2012 2:54 AM, Timon Gehr wrote:Yes, they are. (But a future extension might leave this choice up to 'foo')Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not?Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not?There is no such thing as an attr(foo) int, because attr is not a type constructor.And, whatever you choose for the semantics, what is the sensible, intuitive rule for it?Custom attributes apply to the symbol declaration. Because any symbol is declared just once, there is never any ambiguity. There is no conceptual gap between attr(foo) int x; and attr(bar) struct S{...} Obviously attr(bar) changes S, but there is only one declaration of S.
Apr 06 2012
On 4/6/2012 3:49 AM, Timon Gehr wrote:On 04/06/2012 12:23 PM, Walter Bright wrote:But you said it was added to the *type*.On 4/6/2012 2:54 AM, Timon Gehr wrote:Yes, they are. (But a future extension might leave this choice up to 'foo')Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not?Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not?There is no such thing as an attr(foo) int, because attr is not a type constructor.
Apr 09 2012
On 04/10/2012 12:18 AM, Walter Bright wrote:On 4/6/2012 3:49 AM, Timon Gehr wrote:What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'On 04/06/2012 12:23 PM, Walter Bright wrote:But you said it was added to the *type*.On 4/6/2012 2:54 AM, Timon Gehr wrote:Yes, they are. (But a future extension might leave this choice up to 'foo')Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not?Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not?There is no such thing as an attr(foo) int, because attr is not a type constructor.
Apr 10 2012
On Tue, 10 Apr 2012 06:32:00 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:On 04/10/2012 12:18 AM, Walter Bright wrote:I should clarify that it's *associated* with the type. It should not affect the type in how it functions, at all. For all usages of Foo except to get attributes associated with its declaration, it should be treated as if it doesn't have an attribute on it. So it doesn't affect how the type operates or how it's matched, etc. except in the capacity that you query its attributes. -SteveBut you said it was added to the *type*.What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'
Apr 10 2012
On 04/10/12 12:32, Timon Gehr wrote:On 04/10/2012 12:18 AM, Walter Bright wrote:The last one is the one i'm not sure about. What's the advantage of not reporting 'foo' for 'x'? "Inheriting" the attrs from the type seems attractive, what does separating the attributes achieve in practice? I'm assuming the type attributes do not influence the type in any way. While it would be great if one could also have type-changing attributes [1] in addition to the just annotating ones, i'm not going to propose that - there were too many too complicated proposals in these threads already... artur [1] think "shared" etc, or multiple string types.On 4/6/2012 3:49 AM, Timon Gehr wrote:What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'On 04/06/2012 12:23 PM, Walter Bright wrote:But you said it was added to the *type*.On 4/6/2012 2:54 AM, Timon Gehr wrote:Yes, they are. (But a future extension might leave this choice up to 'foo')Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not?Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not?There is no such thing as an attr(foo) int, because attr is not a type constructor.
Apr 10 2012
On 6 April 2012 13:23, Walter Bright <newshound2 digitalmars.com> wrote:On 4/6/2012 2:54 AM, Timon Gehr wrote:Yes they are the same type.Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.How would: attr(foo) int x; int y; work? Are x and y the same type or not?Now, consider: auto c = b ? x : y;c was not attributed, and has no attributes. blah auto c = b ? x : y; // NOW 'c' is attributed with 'blah', as useless as that is :) Attributes are on the declaration, and not passed around.
Apr 06 2012
On 4/6/2012 4:20 AM, Manu wrote:On 4/6/2012 2:54 AM, Timon Gehr wrote: Should add additional information to the type Foo. Attributes are on the declaration, and not passed around.Right, they are not added to the *type*.
Apr 09 2012
Le 10/04/2012 00:19, Walter Bright a écrit :On 4/6/2012 4:20 AM, Manu wrote:No, they are not, or it will become a crazy mess.On 4/6/2012 2:54 AM, Timon Gehr wrote: Should add additional information to the type Foo. Attributes are on the declaration, and not passed around.Right, they are not added to the *type*.
Apr 10 2012
On Fri, 06 Apr 2012 03:54:15 -0400, Walter Bright = <newshound2 digitalmars.com> wrote:On 4/6/2012 12:49 AM, Alex R=C3=B8nne Petersen wrote:. =What about type declarations? I think those ought to be supported too=E.g. it makes sense to mark an entire type as attr(serializable) (or the ==inverse).That would make it a "type constructor", not a storage class, which we=talked about earlier in the thread. I refer you to that discussion.I think there is a huge misunderstanding here. A type constructor alters a type. Annotations are not type constructors= . for example: class C {} foo class D {} foo C c; foo2 D d; D d2 =3D d; In all these cases, the foo or foo2 affects the *declaration*, not the= = *type*. So: 1. D's type is not affected, it's still class D. But an annotation has = = been stored on the *symbol* D, such that it can be looked up later. 2. annotations on variables do *not* affect the type of the variable. T= he = assignment to d2 works fine. 3. The following symbols have annotations attached to them: C: none D: foo c: foo d: foo2 d2: none Note that d and d2 have no annotations attached even though they are of = = type D. Because the type isn't affected by annotations. An annotation is simply metadata, stored in the compiler, and looked up = = via compiler directives. Optionally (and I would encourage this), = TypeInfo would store annotations on type declarations for retrieval at = runtime. -Steve
Apr 06 2012
On 6 April 2012 15:58, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 06 Apr 2012 03:54:15 -0400, Walter Bright < newshound2 digitalmars.com> wrote: On 4/6/2012 12:49 AM, Alex R=C3=B8nne Petersen wrote:eI think there is a huge misunderstanding here. A type constructor alters a type. Annotations are not type constructors. for example: class C {} foo class D {} foo C c; foo2 D d; D d2 =3D d; In all these cases, the foo or foo2 affects the *declaration*, not the *type*. So: 1. D's type is not affected, it's still class D. But an annotation has been stored on the *symbol* D, such that it can be looked up later. 2. annotations on variables do *not* affect the type of the variable. Th=What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse).That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.assignment to d2 works fine. 3. The following symbols have annotations attached to them: C: none D: foo c: foo d: foo2 d2: none Note that d and d2 have no annotations attached even though they are of type D. Because the type isn't affected by annotations.Just to clarify, typeof(d) and typeof(d2) (ie, both D's) are still annotated with foo, right? This is precisely how I imagine it to be. An annotation is simply metadata, stored in the compiler, and looked up viacompiler directives. Optionally (and I would encourage this), TypeInfo would store annotations on type declarations for retrieval at runtime.I agree, and I would also encourage this.
Apr 06 2012
On Fri, 06 Apr 2012 09:04:58 -0400, Manu <turkeyman gmail.com> wrote:On 6 April 2012 15:58, Steven Schveighoffer <schveiguy yahoo.com> wrote:Correct. -SteveNote that d and d2 have no annotations attached even though they are of type D. Because the type isn't affected by annotations.Just to clarify, typeof(d) and typeof(d2) (ie, both D's) are still annotated with foo, right? This is precisely how I imagine it to be.
Apr 06 2012
On 2012-04-06 14:58, Steven Schveighoffer wrote:An annotation is simply metadata, stored in the compiler, and looked up via compiler directives. Optionally (and I would encourage this), TypeInfo would store annotations on type declarations for retrieval at runtime. -SteveYes, annotations/attributes should be accessible at both compile time and runtime. -- /Jacob Carlborg
Apr 06 2012
On 2012-04-06 09:47, Walter Bright wrote:On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:They need to be attachable to classes, structs, enums and so on as well. -- /Jacob CarlborgAlso, by storage class do you mean it will work only on fields?No. Storage classes work on fields, functions, and variables.
Apr 06 2012
On 6 April 2012 09:47, Walter Bright <newshound2 digitalmars.com> wrote:On 4/5/2012 5:00 AM, Manu wrote:I think this is unnecessarily verbose, although certainly workable as a minimum. Although there is one issue that 'foo' can't store compound data. I'd like to see attributes defined as a special sort of struct, and support constructors, this way you can associate rich data, and you can perform complex expressions (ctfe) within the constructor to set defaults, or calculate other details about the attribute if not specified. replay int x; // this is all that is needed if the attribute associates no variable information // or something associating consideraly more rich information editor("X coordinate", EditType.Slider, Colour.Red, "Verbose description about the thing") // this is still a lot easier to read to me... int x;patterns, Idon't think there should be any mystery over how they should beimplemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 06 2012
On 2012-04-06 08:47, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote: patterns, I > don't think there should be any mystery over how they should be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;I'm not a particular fan of that syntax. I would go with: identifier(key = value/expression) Like: foo(k1 = bar + 1, k2 = bar + 2) int x; If the attribute takes one key-value pair: foo(value = bar + 1) int x; Can be shortened like: foo(bar + 1) int x; And for attributes that don't take any values: foo int x; -- /Jacob Carlborg
Apr 06 2012
On 2012-04-06 08:47, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote: patterns, I > don't think there should be any mystery over how they should be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;Again, this is my proposal: http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_user_defined_attributes_161624.html#N161742 -- /Jacob Carlborg
Apr 06 2012
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression)The identifier in there is a liability because of name conflicts. Instead, use typeof(expression) to identify it. Since two types can't have the same fully qualified name, it will never conflict. Jacob and I disagreed on some details, but both our proposals in the last thread had this in common. Java does it this way, too. Here's the other thread: http://forum.dlang.org/thread/bccwycoexxykfgxvedix forum.dlang.org
Apr 06 2012
On 4/6/12 1:47 AM, Walter Bright wrote:On 4/5/2012 5:00 AM, Manu wrote: patterns, I > don't think there should be any mystery over how they should be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration.You also need means to enumerate attributes. Andrei
Apr 06 2012
Andrei Alexandrescu wrote:On 4/6/12 1:47 AM, Walter Bright wrote:Minimalistically getAttribute*s* should be enough: __traits(getAttributes, x) would return all attributes of x. The rest can be implemented as library templates in std.traits.__traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration.You also need means to enumerate attributes.
Apr 06 2012
On Friday, 6 April 2012 at 15:16:37 UTC, Piotr Szturmaj wrote:__traits(getAttributes, x)Note that my proposal from a couple weeks ago did it this way. getAttributes returned a TypeTuple. You'd loop through it with is(typeof()) to extract a specific one. The key is the type name. The value is whatever your thing evaluated to: attr(10+2) decl; conceptually the same as enum tmp = 10+2; decl.annotations ~= tmp;
Apr 06 2012
I don't want this thread to disappear. The ideas presented here have common= basic features among the nice-to-haves. 1. Attributes add meta data baggage to a symbol 2. This meta data is thought of as a read-only hash (has, get, iterate) 3. Can be queried at compile-time 4. The syntax is concise (i.e. improves over implementing attributes 'manua= lly' with mixins) Now the compiler has solved things (what is a symbol, an AST, ...) in one s= pecific way and to keep it stable and the amount of work within bounds, any= implementation details of attributes that make invasive changes necessary = should be postponed. I don't know the compiler, so it is just my gut feelin= g when I say that annotating local variables could be a refinement to 1) th= at doesn't work well. You get the point. With that in mind it would be good to know exactly what can simply be tacke= d onto the front-end (rather than refactoring a complex part of it). "What = do you want to hear?" I hear you ask. Ok, here is my shameless "since D is = supposed to be" argument: D is supposed to be pragmatic, so I would start w= ith a collection of use cases. Really, "I want attributes to be like this" = is not enough. The use case should be stated in a fashion, that programmers= without experience in the field can follow. The standard use cases for att= ributes are must-haves, the rest can be nice-to-haves. Add to the list, what you need from the attribute system: ** Serialization/RPC ** A relational SQL database comes with meta information on data types. We wan= t to annotate D types with the corresponding types in the DB. This can be u= sed to validate the value ranges at runtime, generate the correct SQL to wo= rk with the tables or even create tables that don't exist already. It is al= so common to establish relations between tables. The struct Parent may have= a 'Child*[]' field and Child a 'Parent*' field. The same applies to RPC. For example we may want to return a bool[] using a= special case in the RPC system for bit arrays: ' Rpc(type =3D RpcType.nati= ve_bit_array, mode =3D RpcMode.async) bool[] foo() { =E2=80=A6 }'. This ann= otation applies to the symbol foo. If make this a more complex return type,= it becomes this: enum RpcMode =E2=80=A6; enum RpcType =E2=80=A6; struct Rpc =E2=80=A6; struct RpcStruct =E2=80=A6; // has a single field, syntax options: // RpcTypeMap(type =3D RpcType.int) // RpcTypeMap(RpcType.int) // RpcTypeMap(int) ? struct RpcTypeMod { RpcType type }; RpcStruct struct MyRet { string name; RpcTypeMap(RpcType.native_bit_array) bool[] flags; } Rpc(mode =3D RpcMode.async) MyRet foo() { =E2=80=A6 } For RPC it is also necessary, to annotate parameters in the same way: void foo( RpcTypeMap(RpcType.native_bit_array) bool[] flags) { =E2=80=A6 } ** Edit object properties in a GUI (as suggested by Manu) ** As seen in GUI builders, often the need occurs to generate bindings to data= structures in order to edit their properties in a convenient user interfac= e. A uint field may be edited using a RGB+Alpha color selector and serializ= ed into a data file. The requirements for the annotations are the same as a= bove. (I know that RTTI would make life easier here, but it isn't a show st= opper.) For these to work it would require: - user annotations to functions/methods/structs/classes - only CTFE support (as annotations don't change at runtime) - no influence on language semantics And I agree with others that it is a good idea to implement annotations as = structured types (POD structs at least) to avoid spelling mistakes and enco= urage IDE support. Just as an idea: Such structs, could contain their own l= ogic. So some annotations which work stand-alone could validate themselves = (invariant()?), print debug msgs, write binding definitions to text files (= if CTFE I/O happens) or actually mixin code if used on structs/classes. But= that's just brain-storming to give an idea why annotations as key/value pa= irs could be unflexible. h what people mostly expect and a good 'template' for D aside from runtim v= s. compile-time issues. thanks for reading :) --=20 Marco
Apr 08 2012
On 2012-04-08 09:27, Marco Leise wrote:I don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.For these to work it would require: - user annotations to functions/methods/structs/classes - only CTFE support (as annotations don't change at runtime)I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime. -- /Jacob Carlborg
Apr 08 2012
Am Sun, 08 Apr 2012 12:44:17 +0200 schrieb Jacob Carlborg <doob me.com>:On 2012-04-08 09:27, Marco Leise wrote:Yeah, it was supposed to mean "it requires CTFE support, runtime support is possible" :) -- MarcoI don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.For these to work it would require: - user annotations to functions/methods/structs/classes - only CTFE support (as annotations don't change at runtime)I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.
Apr 08 2012
Le 08/04/2012 12:44, Jacob Carlborg a écrit :On 2012-04-08 09:27, Marco Leise wrote:If it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.I don't want this thread to disappear. The ideas presented here have common basic features among the nice-to-haves.For these to work it would require: - user annotations to functions/methods/structs/classes - only CTFE support (as annotations don't change at runtime)I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.
Apr 09 2012
On 2012-04-09 23:49, deadalnix wrote:If it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.I'm not saying how it should be implemented, just that it should be accessible at runtime. -- /Jacob Carlborg
Apr 09 2012
On Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-04-09 23:49, deadalnix wrote:I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -SteveIf it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.I'm not saying how it should be implemented, just that it should be accessible at runtime.
Apr 10 2012
On 2012-04-10 13:41, Steven Schveighoffer wrote:On Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:Yeah, I did, hehe :) This thread is getting too long now. -- /Jacob CarlborgOn 2012-04-09 23:49, deadalnix wrote:I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -SteveIf it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.I'm not saying how it should be implemented, just that it should be accessible at runtime.
Apr 10 2012
Am Tue, 10 Apr 2012 13:53:09 +0200 schrieb Jacob Carlborg <doob me.com>:On 2012-04-10 13:41, Steven Schveighoffer wrote:So in the end we more or less agree that Walter and others can implement useful attributes for compile-time, whereas runtime support is nice-to-have (or can be provided by a lib)? My intention is to make it easier for the one who implements them if runtime support proves difficult. -- MarcoOn Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:Yeah, I did, hehe :) This thread is getting too long now.On 2012-04-09 23:49, deadalnix wrote:I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -SteveIf it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.I'm not saying how it should be implemented, just that it should be accessible at runtime.
Apr 10 2012
On 2012-04-10 19:02, Marco Leise wrote:So in the end we more or less agree that Walter and others can implement useful attributes for compile-time, whereas runtime support is nice-to-have (or can be provided by a lib)? My intention is to make it easier for the one who implements them if runtime support proves difficult.Something like that. -- /Jacob Carlborg
Apr 10 2012