digitalmars.D.announce - User Defined Attributes
- Walter Bright (64/64) Nov 05 2012 References:
- Tove (2/7) Nov 06 2012 ["*drool*", "totally perfect awesomeness"] Thanks!
- Walter Bright (4/5) Nov 06 2012 The neato thing is I realized I could just connect the dots on what D al...
- Max Samukha (3/8) Nov 06 2012 Thank you. Now we can stop connecting the dots with hidden
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (8/8) Nov 06 2012 Wow, that's a surprise! Just yesterday I was thinking that it would be
- Walter Bright (5/10) Nov 06 2012 We can debate the syntax. I don't have a store set by this one. I was mo...
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (3/16) Nov 06 2012 Definitely! Thanks a lot for tackling this, to me this seems like
- alex (6/30) Nov 06 2012 @test
- David Nadlinger (20/24) Nov 06 2012 Yes, it is nice to have a working prototype indeed. What is not
- Jacob Carlborg (10/14) Nov 06 2012 Yes, very good point. I don't see why this hasn't been done before, it's...
- Walter Bright (2/14) Nov 06 2012 Because I still think in a linear fashion :-)
- Jacob Carlborg (4/5) Nov 06 2012 Ok, please, please try to start to use more of the features of git.
- xenon325 (7/10) Nov 06 2012 Then you may find article about "git flow" useful:
- kris (3/26) Sep 03 2013 hehe, how on earth were you able to come up with D in the first
- Jacob Carlborg (7/15) Nov 06 2012 I agree, I a syntax like this would have been nicer:
- Walter Bright (5/9) Nov 06 2012 Part of what I was trying to do was minimizing inventing new syntaxes. T...
- Jacob Carlborg (12/23) Nov 06 2012 It depends on how you look at it.
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (5/37) Nov 06 2012 +1
- Walter Bright (4/28) Nov 06 2012 There's a lot more you can do with the ArgumentList syntax than associat...
- Jacob Carlborg (16/29) Nov 06 2012 As I just wrote above, how about this:
- Walter Bright (5/10) Nov 06 2012 Then all UDAs must exist in some shared global name space, and scoping a...
- Jacob Carlborg (8/12) Nov 06 2012 No, what's the difference between this:
- deadalnix (7/17) Nov 06 2012 Let me suggest what have already been suggested by others :
- Walter Bright (11/16) Nov 06 2012 You're right, there is none. That's why using type names as attributes i...
- David Nadlinger (7/12) Nov 06 2012 This doesn't put the @-syntax out of the game, though: @attribute
- Walter Bright (2/6) Nov 06 2012 [ ] vs @( ) is a completely separate issue.
- David Nadlinger (4/5) Nov 06 2012 Yes, you're right, the issues are not related. I just wanted to
- Jacob Carlborg (4/7) Nov 06 2012 Oh, didn't notice until now. I've already added my vote.
- Jacob Carlborg (4/9) Nov 06 2012 Exactly, good point.
- Jacob Carlborg (22/28) Nov 06 2012 Then why allow it? Actually the more I think about it the more I think
- David Nadlinger (6/10) Nov 06 2012 You are right, UDAs must definitely leverage D's module system
- Jacob Carlborg (4/7) Nov 06 2012 Then why allow it in the first place?
- Daniel Murphy (5/13) Nov 06 2012 My thoughts exactly. It reminds me of the horror of C++ exceptions. I
- Walter Bright (2/5) Nov 06 2012 Good analogy. But I'm not sure at this point if that is the right thing ...
- bearophile (8/9) Nov 06 2012 Why?
- Walter Bright (10/16) Nov 06 2012 D was fortunate in having 10 years of experience with C++'s exception sy...
- Jacob Carlborg (5/10) Nov 06 2012 Exactly, then it's better to start with more restrictions and lift them
- Leandro Lucarella (10/24) Nov 07 2012 OK, that's another thing. And maybe a reason for listening to people hav...
- Jacob Carlborg (10/17) Nov 07 2012 I start to more and more think it would be better to explicitly require
- Jonathan M Davis (4/24) Nov 07 2012 Isn't that how it works in Java? It's been a while since I've done much ...
- Jacob Carlborg (5/7) Nov 07 2012 Yes, exactly, just with a slightly different syntax.
- deadalnix (3/24) Nov 07 2012 Yes that was pretty close to what my proposal looked like in the big
- Walter Bright (2/9) Nov 07 2012 Adding a whole new aggregate type is a pretty intrusive and major change...
- deadalnix (9/21) Nov 07 2012 So let's defined in object.d the following :
- Jacob Carlborg (10/19) Nov 07 2012 Is it? Just have it behave as a struct or class. But I guess the
- Walter Bright (5/11) Nov 07 2012 That's a good point, I just want to wryly remark on the consistency argu...
- Jacob Carlborg (4/6) Nov 07 2012 Exactly, the more we can annotated the better :)
- Walter Bright (23/30) Nov 07 2012 There's another aspect to this.
- deadalnix (4/41) Nov 07 2012 Java is mostly compile time (and optionally runtime). See
- Walter Bright (2/5) Nov 07 2012 Doesn't putting compiler hooks in for them make them inherently global?
- Adam D. Ruppe (18/20) Nov 07 2012 One of the previous threads put forth something like this:
- Jacob Carlborg (5/19) Nov 07 2012 Seems like a poor man's replacement for macro annotations:
- deadalnix (2/8) Nov 07 2012 The hook is associated to a given attribute so no it doesn't.
- Walter Bright (2/12) Nov 07 2012 Yes, that makes the attribute global.
- Jacob Carlborg (6/7) Nov 07 2012 I don't actually know how this works in Java but if you are forced to
- Walter Bright (2/6) Nov 08 2012 A plugin would apply globally, wouldn't it?
- Jacob Carlborg (11/12) Nov 08 2012 Yes, but that wouldn't make the attribute global. I just had a quick
- Walter Bright (2/12) Nov 08 2012 I believe that does have the essential effect of making the attribute gl...
- Jacob Carlborg (4/6) Nov 08 2012 I don't understand how.
- Walter Bright (4/8) Nov 08 2012 Because plugins are a global thing. If you have a plugin that deals with...
- Jacob Carlborg (6/9) Nov 08 2012 Well, 'X' is supposed to be the fully qualified name. Can I have my own
- deadalnix (3/14) Nov 09 2012 No it would apply on symbols qualified with a given attribute (provided
- Walter Bright (2/17) Nov 09 2012 Meaning a given attribute can have only one, global, meaning.
- Jacob Carlborg (5/6) Nov 10 2012 Isn't that true for any symbol. Can I have two std.stdio.writeln symbols...
- Walter Bright (4/8) Nov 10 2012 Think of it this way. If I have myString.String, and use the strings in ...
- Jacob Carlborg (11/15) Nov 10 2012 I'm not entirely sure what you're meaning here but if you have two
- Walter Bright (3/15) Nov 13 2012 That is what I mean, and it also applies to a library type which differe...
- Jacob Carlborg (6/8) Nov 13 2012 I think there must be some kind of misunderstanding here. I still don't
- Walter Bright (9/14) Nov 13 2012 We agree that strings can be used globally as attributes with different
- Jacob Carlborg (35/44) Nov 14 2012 I guess it could. But there is no way of preventing the user from doing
- Walter Bright (10/12) Nov 14 2012 I am having a REALLY hard time making my point here.
- Andrei Alexandrescu (5/18) Nov 14 2012 I think a simple way to put this is that attribute name lookup works the...
- Jacob Carlborg (4/7) Nov 15 2012 Exactly.
- Jacob Carlborg (8/14) Nov 15 2012 Sure you _can_ but it would be quite stupid. With user defined types
- Walter Bright (3/16) Nov 16 2012 The whole point of my example was no, you do not necessarily know the me...
- Tove (13/16) Nov 16 2012 Agree. Imagine we have 3 generic libs/modules...
- David Nadlinger (7/24) Nov 16 2012 I don't think this is a valid argument. I challenge you to find a
- Jacob Carlborg (5/16) Nov 16 2012 i don't know what to say anymore. I can only repeat what I've already
- deadalnix (20/33) Nov 16 2012 I seriously feel like I'm in Alice in wonderland here.
- deadalnix (6/19) Nov 10 2012 Thinking of it this way don't make any sense. The whole point of an
- Walter Bright (8/13) Nov 13 2012 I understand that. I just am not convinced of the scope of this issue, a...
- bearophile (22/25) Nov 13 2012 The usage of naked basic types as int and double cause troubles.
- Walter Bright (4/9) Nov 13 2012 I know that you can use custom types instead, and have better type check...
- bearophile (20/21) Nov 13 2012 Walter Bright:
- Walter Bright (3/6) Nov 13 2012 D's typedef is deprecated, as nobody could figure out what it was good f...
- bearophile (5/7) Nov 13 2012 Look better, in both my last posts "Typedef" was
- Leandro Lucarella (10/22) Nov 14 2012 What really amazes me is how you always defend the "will not be included...
- Tove (19/25) Nov 14 2012 There was the example with Thrift...
- Jacob Carlborg (16/40) Nov 14 2012 I assume you mean something like:
- Tove (10/23) Nov 14 2012 well, similar... but beginning with a symbol...
- Leandro Lucarella (23/40) Nov 14 2012 OK, that's just a good example of convenience of allowing native types, ...
- Timon Gehr (8/48) Nov 14 2012 By not telling it that they are for it. Note that the
- Leandro Lucarella (7/63) Nov 15 2012 Yes, but that only tells thrift how to interpret those ints, it doesn't ...
- David Nadlinger (8/23) Nov 14 2012 But what if you want to use that struct with another library as
- Tove (11/36) Nov 14 2012 // in this nested scope, all uints are interpreted as belonging
- Jacob Carlborg (5/14) Nov 14 2012 That doesn't sound like a very good idea. I think it's better to not use...
- David Nadlinger (9/18) Nov 14 2012 »interpreted as belonging to the thrift module« – what do you
- David Nadlinger (9/18) Nov 14 2012 »interpreted as belonging to the thrift module« – what do you
- David Nadlinger (9/18) Nov 14 2012 »interpreted as belonging to the thrift module« – what do you
- Tove (5/9) Nov 15 2012 I disagree, you can always fallback to using user defined
- David Nadlinger (5/8) Nov 15 2012 You are missing the point: In your proposal, if you want to use
- Tove (31/39) Nov 16 2012 no, I implied the solution already... actually there are many
- Walter Bright (6/10) Nov 16 2012 One where its use is entirely inside the scope of a module, i.e. local u...
- deadalnix (5/22) Nov 13 2012 I presented you compile time uses cases for such a mecanism already. See...
- deadalnix (5/24) Nov 10 2012 Yes, it have to. What is the point of attaching an attribute is you
- Walter Bright (1/1) Nov 07 2012 started a new thread on this over in digitalmars.D
- Jacob Carlborg (20/44) Nov 07 2012 This is what I start to like less and less about the current
- Max Samukha (56/68) Nov 08 2012 Could you explain why it is impossible without complicating the
- Max Samukha (2/3) Nov 08 2012 Ignore that line.
- Jacob Carlborg (8/12) Nov 08 2012 I just see no point in allowing random structs and classes acting like
- Max Samukha (10/23) Nov 08 2012 The problem is where to draw the line. There is nothing to stop
- Jacob Carlborg (8/12) Nov 08 2012 Sure, but we don't want to have a comment for every struct indented as
- Andrei Alexandrescu (12/21) Nov 08 2012 Actually there's a stark difference between string attributes and symbol...
- deadalnix (12/32) Nov 07 2012 I don't think that is a good idea. As attribute as they are defined
- Daniel Murphy (21/27) Nov 06 2012 I don't know if it will turn out to be useful either. But if it's left ...
- Timon Gehr (4/33) Nov 07 2012 That is never a given in D.
- deadalnix (2/45) Nov 07 2012 I'd argue that is expression is the problem here, not really the annotat...
- Daniel Murphy (3/8) Nov 07 2012 It makes it harder to do the wrong thing.
- Simen Kjaeraas (14/20) Nov 07 2012 Because string literals are just a special case of literals?
- Jacob Carlborg (6/16) Nov 07 2012 That's why I'm starting to think we need to declare an attribute, see
- deadalnix (4/12) Nov 06 2012 +1
- Walter Bright (5/7) Nov 06 2012 Not really, as an array literal starting an expression is kinda meaningl...
- deadalnix (2/8) Nov 06 2012 Not with UFCS.
- Walter Bright (2/11) Nov 06 2012 You have a point.
- Jakob Ovrum (13/14) Nov 06 2012 It doesn't look like it would be possible to schedule any runtime
- Walter Bright (5/10) Nov 06 2012 Since D allows one to inquire and get a list of symbols, one can then it...
- Jakob Ovrum (10/13) Nov 06 2012 Yes, but somewhere you have to put startup code pointing in the
- dennis luehring (7/12) Nov 06 2012 you're just to deep catched in the
- Jakob Ovrum (3/5) Nov 06 2012 No.
- dennis luehring (2/7) Nov 06 2012 ok not you - but many others
- Johannes Pfau (10/17) Nov 06 2012 The std.benchmark proposal currently requires all benchmark functions to
- Walter Bright (10/17) Nov 06 2012 Consider that you can use a tuple generated elsewhere for a UDA:
- Jacob Carlborg (7/15) Nov 06 2012 Then allow something like this:
- Walter Bright (4/7) Nov 06 2012 To emphasize, the User Defined Attributes thing is completely a compile ...
- Jakob Ovrum (11/15) Nov 06 2012 Problem is that there's no way to do this without having the user
- Walter Bright (2/12) Nov 06 2012 Is that really a problem?
- Jakob Ovrum (4/5) Nov 06 2012 I don't strictly need it for any of my projects, where I'm
- deadalnix (2/18) Nov 06 2012 I'm not sure. How can AOP be implemented on top of that ?
- Maxim Fomin (6/13) Nov 06 2012 Runtime arrtibutes can be implemented as properties in object.d.
- Jakob Ovrum (5/10) Nov 06 2012 I'm not suggesting runtime attributes should be part of the
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (9/27) Nov 06 2012 I see this as a feature in a way. The way C# attributes are sometimes
- Maxim Fomin (3/4) Nov 06 2012 Nice to hear because it was unexpected and was requested
- Walter Bright (2/5) Nov 06 2012 I've been intending to do it for a while now.
- Jonathan M Davis (5/12) Nov 06 2012 I always figured that it was pretty much a given that we'd get it at som...
- Walter Bright (6/9) Nov 06 2012 Anything I can do to make sure that going back to C++ is too terrible to...
- deadalnix (3/14) Nov 06 2012 As soon as this is added, code will use it and bugs in that part will
- Jonas Drewsen (11/11) Nov 06 2012 Wow! This is an early christmas gift.
- Walter Bright (2/12) Nov 06 2012 Yes, you can attach them to other symbols, including user defined types.
- Jonas Drewsen (4/24) Nov 06 2012 Great. Can't wait to play around with this. I think project
- Jens Mueller (29/128) Nov 06 2012 osal_yeah_another_one_163246.html
- Jakob Ovrum (14/18) Nov 06 2012 In the initial discussions, I was hoping that the symbol itself
- Jens Mueller (18/139) Nov 06 2012 oposal_yeah_another_one_163246.html
- Tove (10/10) Nov 06 2012 Tooo much fun! Argh, _must_ _stop_ _playing_ and actually work ;(
- simendsjo (2/13) Nov 06 2012 Or obfuscation :)
- Max Samukha (20/23) Nov 06 2012 Attributes on overloads are critical. Currently fails:
- Walter Bright (2/3) Nov 06 2012 That should work. Will investigate.
- Walter Bright (2/3) Nov 06 2012 Found & fixed. Thanks!
- angel (4/4) Nov 06 2012 How do the attributes interact with inheritance ?
- Walter Bright (2/4) Nov 06 2012 The attributes are for the symbol, not the type.
- Jacob Carlborg (11/19) Nov 06 2012 This is so cool. Although I would have expected it to have a slightly
- Adam D. Ruppe (4/5) Nov 06 2012 We can always use custom types to get this kind of thing.
- Jacob Carlborg (14/17) Nov 06 2012 Right, good point. But I would still like to somehow be able to name an
- Walter Bright (5/13) Nov 06 2012 or:
- Jacob Carlborg (6/12) Nov 06 2012 First, I didn't know you could have an empty enum. Second, that was my
- Walter Bright (5/17) Nov 06 2012 I see your point, but if such was implemented that way, then the UDAs wo...
- Jacob Carlborg (5/10) Nov 06 2012 No, I don't think so, see one of my other replies:
- Adam D. Ruppe (21/23) Nov 06 2012 Hmmm, it didn't work on the most important place for my use case,
- Rory McGuire (4/25) Nov 06 2012 You can put the attribute on the function.
- Adam D. Ruppe (12/13) Nov 06 2012 Yeah, but that's an awfully roundabout way to add an attribute to
- Gor Gyolchanyan (42/55) Nov 06 2012 What if the data in the attribute needs to be specific to the
- Jacob Carlborg (4/41) Nov 06 2012 I like this proposal as well.
- bearophile (28/34) Nov 06 2012 For the syntax maybe it's better something like @() instead of
- Walter Bright (5/18) Nov 06 2012 It would be a significant extension, and so I'd like to see a compelling...
- bearophile (12/17) Nov 06 2012 Right. Combined with the trait to read function arguments, it's
- Walter Bright (7/20) Nov 06 2012 Ok, I ask again, what use case for a UDA is there for function parameter...
- David Nadlinger (33/36) Nov 06 2012 What »IDL« are you referring to here? At least as far as I am
- dennis luehring (2/17) Nov 06 2012 perfect example - thx alot
- dennis luehring (2/13) Nov 06 2012 http://svn.apache.org/repos/asf/thrift/trunk/tutorial/tutorial.thrift
- David Nadlinger (6/19) Nov 06 2012 (Note that this is actual code that has the intended result with
- Walter Bright (6/37) Nov 06 2012 Back in the olden days, Microsoft released a language called IDL (Interf...
- David Nadlinger (6/11) Nov 06 2012 It means that ›a‹ has type i32 and is the parameter with ID
-
Walter Bright
(4/13)
Nov 06 2012
Ok, but a type is not a UDA
. - David Nadlinger (20/32) Nov 06 2012 That was never my point. I could have also just said »Parameters
- bearophile (41/43) Nov 06 2012 I am still referring to this:
- Walter Bright (7/13) Nov 06 2012 x is a value type, and it is already copied. And if you did want to copy...
- bearophile (65/79) Nov 06 2012 Walter Bright:
- Adam D. Ruppe (21/23) Nov 06 2012 What do you consider to be compelling use cases for UDAs on
- Adam D. Ruppe (12/14) Nov 06 2012 BTW we could conceivably do:
- Walter Bright (7/20) Nov 06 2012 That looks like it can work. It's an interesting idea.
- Paulo Pinto (6/11) Nov 06 2012 Having seen how annotations for function arguments in Java 8 might look
- Timon Gehr (3/9) Nov 06 2012 The use cases are the same as for other declarations. Parameter
- dennis luehring (8/16) Nov 06 2012 sad - but its still very young feature :)
- Walter Bright (4/19) Nov 06 2012 But there's already out=write, read=all of them, read_write=ref, copy=no...
- Adam D. Ruppe (12/13) Nov 06 2012 It's pretty much the same as anywhere else: to add useful data
- dennis luehring (12/32) Nov 06 2012 parameter
- Walter Bright (4/29) Nov 06 2012 But D already has parameter attributes that cover those bases. What woul...
- dennis luehring (9/39) Nov 06 2012 just 2 questions:
- Walter Bright (5/11) Nov 06 2012 It adds significant complexity. I don't think it's a good idea to add
- dennis luehring (9/17) Nov 06 2012 parameters
- deadalnix (3/20) Nov 06 2012 It remove complexity in the sens it remove special cases.
- Timon Gehr (2/27) Nov 06 2012 But almost none. It is easy to get right.
- Tove (9/18) Nov 06 2012 Hmmm, actually it doesn't work in plain function/block scope
- Walter Bright (2/3) Nov 06 2012 Right, I don't see a compelling purpose for that, either.
- Tove (3/7) Nov 06 2012 Hmm, what about library based GC annotations?
- Walter Bright (2/9) Nov 06 2012 I have no idea how you could make that work.
- Paulo Pinto (5/17) Nov 06 2012 I can only see it work if the runtime is aware of magic annotations,
- Walter Bright (2/4) Nov 06 2012 It didn't occur to me to enable that.
- deadalnix (2/7) Nov 06 2012 It should work everywhere or not work at all.
- Walter Bright (4/12) Nov 06 2012 You can't have @pure attributes on function parameters, either. Paramete...
- dennis luehring (8/20) Nov 06 2012 Parameters don't
- Walter Bright (10/13) Nov 06 2012 I believe this is the wrong question. For a new feature, the question sh...
- deadalnix (3/11) Nov 06 2012 No. It is needed to annotate symbols, uses cases are numerous. Now, if
- Timon Gehr (5/14) Nov 06 2012 The same holds for arbitrary restrictions.
- Max Samukha (3/22) Nov 06 2012 Exactly. Looking forward to complaints about impossibility to
- Max Samukha (6/22) Nov 06 2012 C# allows custom attributes on function parameters, including the
- Walter Bright (4/7) Nov 06 2012 Thank you. Under the "Remarks" section they give some good examples.
- Max Samukha (5/8) Nov 06 2012 Theoretically there might be cases requiring an attribute of the
- Walter Bright (3/5) Nov 06 2012 Not a problem, as you'd search the tuple for the attribute that matters ...
- Max Samukha (12/20) Nov 06 2012 By "the same class" I meant:
- Walter Bright (2/5) Nov 06 2012 Make SomeFunkyID a parameter to a ReturnOnly template that you've define...
- Max Samukha (9/17) Nov 06 2012 Right. However, the discussion is about adding real attributes to
- Jacob Carlborg (9/14) Nov 06 2012 Yes it does:
- Max Samukha (2/7) Nov 06 2012 Yep, C# attributes can be restricted to specific targets as well.
- nazriel (35/38) Nov 06 2012 I tried to build DMD git for dpaste, so people can play with UDA
- Walter Bright (3/5) Nov 06 2012 The auto tester shows it's working.
- deadalnix (14/86) Nov 06 2012 OK, I may break all the happiness of that news but . . .
- Walter Bright (4/11) Nov 06 2012 Are you aware of the test suite and the auto-tester?
- deadalnix (15/32) Nov 06 2012 If it is the only problem, we have a pandemic spread of hallucinogen
- Don Clugston (7/46) Nov 07 2012 If you mean, we should be working on getting the existing stuff working
- Leandro Lucarella (11/21) Nov 07 2012 100% agree. It might make a little sense if it were in an experimental b...
- deadalnix (9/15) Nov 07 2012 That is a good part of my point. The other part being that surprise
- John Chapman (5/5) Nov 06 2012 Enjoying playing with the new stuff.
- Walter Bright (2/5) Nov 06 2012 Can you show an example code snippet?
- John Chapman (42/49) Nov 06 2012 It would save having to read the registry and load type libraries
- Walter Bright (4/13) Nov 06 2012 I could use a compilable one :-)
- David Nadlinger (5/12) Nov 06 2012 For further examples on how annotations on interfaces would be
- Chris Nicholson-Sauls (44/44) Nov 06 2012 Just thinking out loud...
- Jonathan M Davis (8/23) Nov 06 2012 Wait. That's a TypeTuple. Tuple is completely different. You're going to...
- Walter Bright (1/1) Nov 07 2012 New version up now with a couple reported problems with UDA fixed.
- Tove (10/12) Nov 08 2012 I may have found a little glitch...?
- Nick Sabalausky (2/2) Nov 07 2012 First of all: Awesome.
- Jonathan M Davis (5/8) Nov 07 2012 In Announce? Probably. In all of the D groups? Probably not. There have ...
- Walter Bright (2/4) Nov 07 2012 The historical UDA threads have been large, too.
- Kapps (18/18) Nov 07 2012 Awesome. Lack of UDA has really caused some very ugly workarounds
- Walter Bright (2/13) Nov 07 2012 See new thread I started on this in digitalmars.D.
References: http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor). You can download it here and try it out: http://ftp.digitalmars.com/dmd2beta.zip As a bonus, that beta also can generate Win64 executables, and you can even symbolically debug them with VS! (Thanks to Rainer Schütze for his invaluable help with that). Here's the rather skimpy and lame spec I banged out: ===================================================== User Defined Attributes ----------------------- User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration. These attributes can then be queried, extracted, and manipulated at compile time. There is no runtime component to them. Grammatically, a UDA is a StorageClass: StorageClass: UserDefinedAttribute UserDefinedAttribute: [ ArgumentList ] And looks like: [ 3 ] int a; [ "string", 7 ]: int b; If there are multiple UDAs in scope for a declaration, they are concatenated: [ 1 ] { [ 2 ] int a; // has UDA's [1,2] [ "string" ] int b; // has UDA's [1,"string"] } UDA's can be extracted into an expression tuple using __traits: [ 'c' ] string s; pragma(msg, __traits(getAttributes, s)); prints: tuple('c') If there are no user defined attributes for the symbol, an empty tuple is returned. The expression tuple can be turned into a manipulatable tuple: template Tuple(T...) { alias T Tuple; } enum EEE = 7; ["hello"] struct SSS { } [3] { [4][EEE][SSS] int foo; } alias Tuple!(__traits(getAttributes, foo)) TP; pragma(msg, TP); pragma(msg, TP[2]); prints: tuple(3,4,7,(SSS)) 7 and of course the tuple types can be used to declare things: TP[3] a; // a is declared as an SSS The attribute of the type name is not the same as the attribute of the variable: pragma(msg, __traits(getAttributes, typeof(a)); prints: tuple("hello") Of course, the real value of UDA's is to be able to create user defined types with specific values. Having attribute values of basic types does not scale. The attribute tuples can be manipulated like any other tuple, and can be passed as the argument list to a template. Whether the attributes are values or types is up to the user, and whether later attributes accumulate or override earlier ones is also up to how the user interprets them.
Nov 05 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:References: http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE["*drool*", "totally perfect awesomeness"] Thanks!
Nov 06 2012
On 11/6/2012 12:15 AM, Tove wrote:["*drool*", "totally perfect awesomeness"] Thanks!The neato thing is I realized I could just connect the dots on what D already does well - CTFE, tuples, and templates. The actual features can now be added by library routines.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:20:42 UTC, Walter Bright wrote:On 11/6/2012 12:15 AM, Tove wrote:Thank you. Now we can stop connecting the dots with hidden declaration hacks. Yay!["*drool*", "totally perfect awesomeness"] Thanks!The neato thing is I realized I could just connect the dots on what D already does well - CTFE, tuples, and templates. The actual features can now be added by library routines.
Nov 06 2012
Wow, that's a surprise! Just yesterday I was thinking that it would be really nice to have them for a piece of code ;) But shouldn't we keep the syntax closer to normal attributes and other languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'
Nov 06 2012
On 11/6/2012 12:20 AM, Sönke Ludwig wrote:> But shouldn't we keep the syntax closer to normal attributes and otherlanguages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'We can debate the syntax. I don't have a store set by this one. I was more interested in getting the semantics right. Anyhow, it's nice to have a working prototype to experiment with rather than a paper airplane.
Nov 06 2012
Am 06.11.2012 09:26, schrieb Walter Bright:On 11/6/2012 12:20 AM, Sönke Ludwig wrote:> But shouldn't we keep the syntax closer to normal attributes and otherDefinitely! Thanks a lot for tackling this, to me this seems like something that can get a real killer feature for the language!languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'We can debate the syntax. I don't have a store set by this one. I was more interested in getting the semantics right. Anyhow, it's nice to have a working prototype to experiment with rather than a paper airplane.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:55:06 UTC, Sönke Ludwig wrote:Am 06.11.2012 09:26, schrieb Walter Bright:test void myUnittest() { } Uh yeah, that would be awesome!On 11/6/2012 12:20 AM, Sönke Ludwig wrote:> But shouldn't we keep the syntax closer to normal attributes and otherDefinitely! Thanks a lot for tackling this, to me this seems like something that can get a real killer feature for the language!languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'We can debate the syntax. I don't have a store set by this one. I was more interested in getting the semantics right. Anyhow, it's nice to have a working prototype to experiment with rather than a paper airplane.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:26:14 UTC, Walter Bright wrote:We can debate the syntax. I don't have a store set by this one. I was more interested in getting the semantics right. Anyhow, it's nice to have a working prototype to experiment with rather than a paper airplane.Yes, it is nice to have a working prototype indeed. What is not so nice in my opinion, however, is that this first prototype straight to Git master, without any prior evaluation, at a time where the general goal is to stabilize the language. What if the implementation doesn't pan out as planned? Do you want to delay the next release until the new feature has become stable? It can be a big mess to hastily revert the commits again after the same areas might have been touched by other, unrelated sets of changes. This is exactly what branches are good for. People can experiment with the new additions and shortcomings can be fixed, and then, if everything looks solid, the branch can be merged back into master – without affecting work on the main branch in the meantime (it has been three months since the last release, and there are quite a few open regressions). Even Andrei submits pull requests for any non-trivial Phobos changes. Might I suggest adopting a similar policy for DMD, at least when language changes/additions are concerned? David
Nov 06 2012
On 2012-11-06 18:00, David Nadlinger wrote:Yes, it is nice to have a working prototype indeed. What is not so nice in my opinion, however, is that this first prototype straight to Git master, without any prior evaluation, at a time where the general goal is to stabilize the language.Yes, very good point. I don't see why this hasn't been done before, it's dead easy. Just use: $ git checkout -b uda $ git commit -a -m "Add support for user defined attributes" $ git push origin uda Walter, why aren't you using branches for these kind of things? -- /Jacob Carlborg
Nov 06 2012
On 11/6/2012 10:10 AM, Jacob Carlborg wrote:On 2012-11-06 18:00, David Nadlinger wrote:Because I still think in a linear fashion :-)Yes, it is nice to have a working prototype indeed. What is not so nice in my opinion, however, is that this first prototype straight to Git master, without any prior evaluation, at a time where the general goal is to stabilize the language.Yes, very good point. I don't see why this hasn't been done before, it's dead easy. Just use: $ git checkout -b uda $ git commit -a -m "Add support for user defined attributes" $ git push origin uda Walter, why aren't you using branches for these kind of things?
Nov 06 2012
On 2012-11-06 19:49, Walter Bright wrote:Because I still think in a linear fashion :-)Ok, please, please try to start to use more of the features of git. -- /Jacob Carlborg
Nov 06 2012
On Tuesday, 6 November 2012 at 18:49:22 UTC, Walter Bright wrote:On 11/6/2012 10:10 AM, Jacob Carlborg wrote:Then you may find article about "git flow" useful: http://nvie.com/posts/a-successful-git-branching-model/ It's basically enough to look at the picture at the beginning to get the idea. git extensions from the author to support that branching model: https://github.com/nvie/gitflowWalter, why aren't you using branches for these kind of things?Because I still think in a linear fashion :-)
Nov 06 2012
On Tuesday, 6 November 2012 at 18:49:22 UTC, Walter Bright wrote:On 11/6/2012 10:10 AM, Jacob Carlborg wrote:hehe, how on earth were you able to come up with D in the first place then? ;-pOn 2012-11-06 18:00, David Nadlinger wrote:Because I still think in a linear fashion :-)Yes, it is nice to have a working prototype indeed. What is not so nice in my opinion, however, is that this first prototype straight to Git master, without any prior evaluation, at a time where the general goal is to stabilize the language.Yes, very good point. I don't see why this hasn't been done before, it's dead easy. Just use: $ git checkout -b uda $ git commit -a -m "Add support for user defined attributes" $ git push origin uda Walter, why aren't you using branches for these kind of things?
Sep 03 2013
On 2012-11-06 09:20, Sönke Ludwig wrote:Wow, that's a surprise! Just yesterday I was thinking that it would be really nice to have them for a piece of code ;) But shouldn't we keep the syntax closer to normal attributes and other languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'I agree, I a syntax like this would have been nicer: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype("value") int b; mtype int c; -- /Jacob Carlborg
Nov 06 2012
On 11/6/2012 5:04 AM, Jacob Carlborg wrote:I agree, I a syntax like this would have been nicer: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype("value") int b; mtype int c;Part of what I was trying to do was minimizing inventing new syntaxes. The [ ArgumentList ] invents nothing new but the brackets. Your proposal is both a new syntax, and it can only do key/value pairs - nothing else.
Nov 06 2012
On 2012-11-06 16:39, Walter Bright wrote:On 11/6/2012 5:04 AM, Jacob Carlborg wrote:It depends on how you look at it. * mtype - is the same syntax as the current syntax for attributes * mtype("key" : "value") - Uses the above in combination with the syntax for associative array literals How about this then: mtype("foo", 3, "bar") int a; And have the argument list be optional? I really like to have a short nice looking syntax for the simple use cases, i.e. mtype int b; -- /Jacob CarlborgI agree, I a syntax like this would have been nicer: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype("value") int b; mtype int c;Part of what I was trying to do was minimizing inventing new syntaxes. The [ ArgumentList ] invents nothing new but the brackets. Your proposal is both a new syntax, and it can only do key/value pairs - nothing else.
Nov 06 2012
Am 06.11.2012 16:55, schrieb Jacob Carlborg:On 2012-11-06 16:39, Walter Bright wrote:+1 Also, if mtype is a template, it could naturally be mtype!(1, 2, 3). Without the '!' it would be a function that is evaluated at CT. And just mtype would yield an alias of mtype.On 11/6/2012 5:04 AM, Jacob Carlborg wrote:It depends on how you look at it. * mtype - is the same syntax as the current syntax for attributes * mtype("key" : "value") - Uses the above in combination with the syntax for associative array literals How about this then: mtype("foo", 3, "bar") int a; And have the argument list be optional? I really like to have a short nice looking syntax for the simple use cases, i.e. mtype int b;I agree, I a syntax like this would have been nicer: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype("value") int b; mtype int c;Part of what I was trying to do was minimizing inventing new syntaxes. The [ ArgumentList ] invents nothing new but the brackets. Your proposal is both a new syntax, and it can only do key/value pairs - nothing else.
Nov 06 2012
On 11/6/2012 7:55 AM, Jacob Carlborg wrote:On 2012-11-06 16:39, Walter Bright wrote:There's a lot more you can do with the ArgumentList syntax than associative arrays. Furthermore, there remains the problem of how mtype fits into the name scoping system.On 11/6/2012 5:04 AM, Jacob Carlborg wrote:It depends on how you look at it. * mtype - is the same syntax as the current syntax for attributes * mtype("key" : "value") - Uses the above in combination with the syntax for associative array literals How about this then: mtype("foo", 3, "bar") int a; And have the argument list be optional? I really like to have a short nice looking syntax for the simple use cases, i.e. mtype int b;I agree, I a syntax like this would have been nicer: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype("value") int b; mtype int c;Part of what I was trying to do was minimizing inventing new syntaxes. The [ ArgumentList ] invents nothing new but the brackets. Your proposal is both a new syntax, and it can only do key/value pairs - nothing else.
Nov 06 2012
On 2012-11-06 17:04, Walter Bright wrote:As I just wrote above, how about this: mtype("foo", 3, "bar") int a; mtype int b; In the above example, the values in the parentheses would be the same as your ArgumentList. The important thing here is also to have the ArgumentList and parentheses be optional. What's the issue with the name scoping system? That the user defined attributes will conflict with already existing attributes? You'll have the same problem with keywords. Perhaps that's why attributes where created, to have a new namespace for keywords. Even if they might not be the same internally for the compiler it's the same for the user/developer. Just as we have operator overloading to allow user defined types to look like built-in types we/I want the same thing for user defined attributes. -- /Jacob CarlborgHow about this then: mtype("foo", 3, "bar") int a; And have the argument list be optional? I really like to have a short nice looking syntax for the simple use cases, i.e. mtype int b;There's a lot more you can do with the ArgumentList syntax than associative arrays. Furthermore, there remains the problem of how mtype fits into the name scoping system.
Nov 06 2012
On 11/6/2012 10:01 AM, Jacob Carlborg wrote:What's the issue with the name scoping system? That the user defined attributes will conflict with already existing attributes? You'll have the same problem with keywords. Perhaps that's why attributes where created, to have a new namespace for keywords. Even if they might not be the same internally for the compiler it's the same for the user/developer.Then all UDAs must exist in some shared global name space, and scoping and encapsulation becomes like it is in C, i.e. every_body_writes_their_names_like_this and hopes it doesn't conflict with someone else's names.
Nov 06 2012
On 2012-11-06 19:16, Walter Bright wrote:Then all UDAs must exist in some shared global name space, and scoping and encapsulation becomes like it is in C, i.e. every_body_writes_their_names_like_this and hopes it doesn't conflict with someone else's names.No, what's the difference between this: every_body_writes_their_names_like_this int a; And ["every_body_writes_their_names_like_this"] int a; None. -- /Jacob Carlborg
Nov 06 2012
Le 06/11/2012 19:19, Jacob Carlborg a écrit :On 2012-11-06 19:16, Walter Bright wrote:Let me suggest what have already been suggested by others : identifier(parameters) identifier is resolved as any identifier is. It allow for disambiguation. It also allow for a lib to provide its own attributes types without colliding which other (it is easy to filter the tuple for attribute with the right type).Then all UDAs must exist in some shared global name space, and scoping and encapsulation becomes like it is in C, i.e. every_body_writes_their_names_like_this and hopes it doesn't conflict with someone else's names.No, what's the difference between this: every_body_writes_their_names_like_this int a; And ["every_body_writes_their_names_like_this"] int a; None.
Nov 06 2012
On 11/6/2012 10:19 AM, Jacob Carlborg wrote:No, what's the difference between this: every_body_writes_their_names_like_this int a; And ["every_body_writes_their_names_like_this"] int a; None.You're right, there is none. That's why using type names as attributes is more scalable and robust. I understand your desire to have attributes be implicitly declared, but I think that implicit declarations have historically been seductive, and much later were realized to be a mistake. This pattern has happened over and over :-) For example: seperate and sometime later: separate How long will it be before that bug is noticed?
Nov 06 2012
On Tuesday, 6 November 2012 at 18:36:54 UTC, Walter Bright wrote:For example: seperate and sometime later: separate How long will it be before that bug is noticed?This doesn't put the -syntax out of the game, though: attribute could just be equivalent to (attribute) and look up "attribute" in the local scope, following the usual rules. This would look much better than the bracket syntax, at least in my opinion, and avoid confusion with array literals. David
Nov 06 2012
On 11/6/2012 10:45 AM, David Nadlinger wrote:This doesn't put the -syntax out of the game, though: attribute could just be equivalent to (attribute) and look up "attribute" in the local scope, following the usual rules. This would look much better than the bracket syntax, at least in my opinion, and avoid confusion with array literals.[ ] vs ( ) is a completely separate issue.
Nov 06 2012
On Tuesday, 6 November 2012 at 19:36:18 UTC, Walter Bright wrote:[ ] vs ( ) is a completely separate issue.Yes, you're right, the issues are not related. I just wanted to share the idea, and your dm.D thread didn't exist back then. David
Nov 06 2012
On 2012-11-06 20:44, David Nadlinger wrote:Yes, you're right, the issues are not related. I just wanted to share the idea, and your dm.D thread didn't exist back then. DavidOh, didn't notice until now. I've already added my vote. -- /Jacob Carlborg
Nov 06 2012
On 2012-11-06 19:45, David Nadlinger wrote:This doesn't put the -syntax out of the game, though: attribute could just be equivalent to (attribute) and look up "attribute" in the local scope, following the usual rules. This would look much better than the bracket syntax, at least in my opinion, and avoid confusion with array literals.Exactly, good point. -- /Jacob Carlborg
Nov 06 2012
On 2012-11-06 19:36, Walter Bright wrote:You're right, there is none. That's why using type names as attributes is more scalable and robust.Then why allow it? Actually the more I think about it the more I think you're right in that it's better to use a proper symbol or type name. But I still don't like the syntax.I understand your desire to have attributes be implicitly declared, but I think that implicit declarations have historically been seductive, and much later were realized to be a mistake. This pattern has happened over and over :-)Actually I don't. I was just trying to stay close to your implementation. This is one of my proposals, from a one the threads you linked to: http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_user_defined_attributes_161624.html#N161742 In that proposal you have to clearly define an attribute, like: attribute class serializable { } attribute class name { string fieldName; } serializable class FooBar { name("foo") int bar; } "serializable" and "name" would be symbols you can import have the same name look up rules any other symbol. -- /Jacob Carlborg
Nov 06 2012
On Tuesday, 6 November 2012 at 18:16:15 UTC, Walter Bright wrote:Then all UDAs must exist in some shared global name space, and scoping and encapsulation becomes like it is in C, i.e. every_body_writes_their_names_like_this and hopes it doesn't conflict with someone else's names.You are right, UDAs must definitely leverage D's module system for encapsulation/disambiguation. Use of string literals (which are intrinsically »global«) as annotations needs to be explicitly discouraged. David
Nov 06 2012
On 2012-11-06 19:24, David Nadlinger wrote:You are right, UDAs must definitely leverage D's module system for encapsulation/disambiguation. Use of string literals (which are intrinsically »global«) as annotations needs to be explicitly discouraged.Then why allow it in the first place? -- /Jacob Carlborg
Nov 06 2012
"Jacob Carlborg" <doob me.com> wrote in message news:k7bp22$1rsc$3 digitalmars.com...On 2012-11-06 19:24, David Nadlinger wrote:My thoughts exactly. It reminds me of the horror of C++ exceptions. I think it would be reasonable to require every annotation is a struct or class.You are right, UDAs must definitely leverage D's module system for encapsulation/disambiguation. Use of string literals (which are intrinsically »global«) as annotations needs to be explicitly discouraged.Then why allow it in the first place? -- /Jacob Carlborg
Nov 06 2012
On 11/6/2012 6:10 PM, Daniel Murphy wrote:My thoughts exactly. It reminds me of the horror of C++ exceptions. I think it would be reasonable to require every annotation is a struct or class.Good analogy. But I'm not sure at this point if that is the right thing to do.
Nov 06 2012
Walter Bright:But I'm not sure at this point if that is the right thing to do.Why? [If you decide to restrict UDAs, then later it will be easy to extend them, it will not break code. While doing the opposite break code. It's you the one that has taught me to design things this way :-) ] Bye, bearophile
Nov 06 2012
On 11/6/2012 7:52 PM, bearophile wrote:Walter Bright:D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.But I'm not sure at this point if that is the right thing to do.Why?[If you decide to restrict UDAs, then later it will be easy to extend them, it will not break code. While doing the opposite break code. It's you the one that has taught me to design things this way :-) ]It's a good point, but I have no experience with UDAs. There may be emergent behavior with these features that is completely unexpected, and we wouldn't find out about it without having it there. Yes, I know it's a risk. (And it was a no-brainer to restrict the exception types. But one must be careful in drawing analogies in programming, as different things are, well, different and can be different in unexpected, surprising ways.)
Nov 06 2012
On 2012-11-07 05:19, Walter Bright wrote:On 11/6/2012 7:52 PM, bearophile wrote:It's a good point, but I have no experience with UDAs. There may be emergent behavior with these features that is completely unexpected, and we wouldn't find out about it without having it there. Yes, I know it's a risk.Exactly, then it's better to start with more restrictions and lift them later as it's needed. -- /Jacob Carlborg
Nov 06 2012
Walter Bright, el 6 de November a las 20:19 me escribiste:On 11/6/2012 7:52 PM, bearophile wrote:What? UDAs has been for quite a long time out in the wild, just not in C++.Walter Bright:D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.But I'm not sure at this point if that is the right thing to do.Why?OK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language). --[If you decide to restrict UDAs, then later it will be easy to extend them, it will not break code. While doing the opposite break code. It's you the one that has taught me to design things this way :-) ]It's a good point, but I have no experience with UDAs.
Nov 07 2012
On 2012-11-07 12:05, Leandro Lucarella wrote:OK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).I start to more and more think it would be better to explicitly require the developer to declare an attribute, like: attribute foo { string name; } foo("asd") int a; -- /Jacob Carlborg
Nov 07 2012
On Wednesday, November 07, 2012 13:01:52 Jacob Carlborg wrote:On 2012-11-07 12:05, Leandro Lucarella wrote:Isn't that how it works in Java? It's been a while since I've done much with Java, but IIRC that's essentially how it works in Java. - Jonathan M DavisOK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).I start to more and more think it would be better to explicitly require the developer to declare an attribute, like: attribute foo { string name; } foo("asd") int a;
Nov 07 2012
On 2012-11-07 13:08, Jonathan M Davis wrote:Isn't that how it works in Java? It's been a while since I've done much with Java, but IIRC that's essentially how it works in Java.Yes, exactly, just with a slightly different syntax. http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html -- /Jacob Carlborg
Nov 07 2012
Le 07/11/2012 13:01, Jacob Carlborg a écrit :On 2012-11-07 12:05, Leandro Lucarella wrote:Yes that was pretty close to what my proposal looked like in the big annotation thread, except I used ttribute .OK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).I start to more and more think it would be better to explicitly require the developer to declare an attribute, like: attribute foo { string name; } foo("asd") int a;
Nov 07 2012
On 11/7/2012 4:01 AM, Jacob Carlborg wrote:I start to more and more think it would be better to explicitly require the developer to declare an attribute, like: attribute foo { string name; } foo("asd") int a;Adding a whole new aggregate type is a pretty intrusive and major change.
Nov 07 2012
Le 07/11/2012 21:35, Walter Bright a écrit :On 11/7/2012 4:01 AM, Jacob Carlborg wrote:So let's defined in object.d the following : attribute struct attribute {} And then mark as attribute anything that may used as attribute. attribute struct foo { string name; } foo("asd") int a; If wasn't marked as attribute, it wouldn't be an valid attribute.I start to more and more think it would be better to explicitly require the developer to declare an attribute, like: attribute foo { string name; } foo("asd") int a;Adding a whole new aggregate type is a pretty intrusive and major change.
Nov 07 2012
On 2012-11-07 21:38, deadalnix wrote:Is it? Just have it behave as a struct or class. But I guess the suggestion below is just as good.Adding a whole new aggregate type is a pretty intrusive and major change.So let's defined in object.d the following : attribute struct attribute {} And then mark as attribute anything that may used as attribute. attribute struct foo { string name; } foo("asd") int a; If wasn't marked as attribute, it wouldn't be an valid attribute.I would be happy with this approach as well. But how much difference would it actually be to have: attribute foo { string name; } -- /Jacob Carlborg
Nov 07 2012
On 11/7/2012 3:05 AM, Leandro Lucarella wrote:For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same.That's a good point, I just want to wryly remark on the consistency argument that UDAs should work everywhere, but the inconsistency argument that they should not work for basic types :-)I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).Just functions? I thought one big use of UDAs was to mark classes as "serializable".
Nov 07 2012
On 2012-11-07 21:41, Walter Bright wrote:Just functions? I thought one big use of UDAs was to mark classes as "serializable".Exactly, the more we can annotated the better :) -- /Jacob Carlborg
Nov 07 2012
On 11/7/2012 3:05 AM, Leandro Lucarella wrote:OK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).There's another aspect to this. D's UDAs are a purely compile time system, attaching arbitrary metadata to specific symbols. The other UDA systems I'm aware of appear to be runtime systems. This implies the use cases will be different - how, I don't really know. But I don't know of any other compile time UDA system. Experience with runtime systems may not be as applicable. Another interesting data point is CTFE. C++11 has CTFE, but it was deliberately crippled and burdened with "constexpr". From what I read, this was out of fear that it would turn out to be an overused and overabused feature. Of course, this turned out to be a large error. One last thing. Sure, string attributes can (and surely would be) used for different purposes in different libraries. The presumption is that this would cause a conflict. But would it? There are two aspects to a UDA - the attribute itself, and the symbol it is attached to. In order to get the UDA for a symbol, one has to look up the symbol. There isn't a global repository of symbols in D. You'd have to say "I want to look in module X for symbols." Why would you look in module X for an attribute that you have no reason to believe applies to symbols from X? How would an attribute for module X's symbols leak out of X on their own? It's not quite analogous to exceptions, because arbitrary exceptions thrown from module X can flow through your code even though you have no idea module X even exists.
Nov 07 2012
Le 07/11/2012 23:20, Walter Bright a écrit :On 11/7/2012 3:05 AM, Leandro Lucarella wrote:Java is mostly compile time (and optionally runtime). See http://projectlombok.org/ for what can be done at compile time with attributes + compiler hooks.OK, that's another thing. And maybe a reason for listening to people having more experience with UDAs than you. For me the analogy with Exceptions is pretty good. The issues an conveniences of throwing anything or annotating a symbol with anything instead of just type are pretty much the same. I only see functions making sense to be accepted as annotations too (that's what Python do with annotations, annotation symbol is the same as symbol = annotation(symbol), but is quite a different language).There's another aspect to this. D's UDAs are a purely compile time system, attaching arbitrary metadata to specific symbols. The other UDA systems I'm aware of appear to be runtime systems. This implies the use cases will be different - how, I don't really know. But I don't know of any other compile time UDA system. Experience with runtime systems may not be as applicable.Another interesting data point is CTFE. C++11 has CTFE, but it was deliberately crippled and burdened with "constexpr". From what I read, this was out of fear that it would turn out to be an overused and overabused feature. Of course, this turned out to be a large error. One last thing. Sure, string attributes can (and surely would be) used for different purposes in different libraries. The presumption is that this would cause a conflict. But would it? There are two aspects to a UDA - the attribute itself, and the symbol it is attached to. In order to get the UDA for a symbol, one has to look up the symbol. There isn't a global repository of symbols in D. You'd have to say "I want to look in module X for symbols." Why would you look in module X for an attribute that you have no reason to believe applies to symbols from X? How would an attribute for module X's symbols leak out of X on their own? It's not quite analogous to exceptions, because arbitrary exceptions thrown from module X can flow through your code even though you have no idea module X even exists.
Nov 07 2012
On 11/7/2012 2:40 PM, deadalnix wrote:Java is mostly compile time (and optionally runtime). See http://projectlombok.org/ for what can be done at compile time with attributes + compiler hooks.Doesn't putting compiler hooks in for them make them inherently global?
Nov 07 2012
On Wednesday, 7 November 2012 at 23:17:24 UTC, Walter Bright wrote:Doesn't putting compiler hooks in for them make them inherently global?One of the previous threads put forth something like this: template MyAttribute(alias subject, T... arguments) { /* some implementation */ The attribute is a template that replaces the declaration. So you type: [MyAttribute("foo")] class Something {} And the compiler rewrites that to: class __anonymous_Something {} alias Something = MyAttribute!(__anonymous_Something, "foo"); ... or something like that. I'm going off memory here. But then you can use the template to do whatever you'd normally do with a template. For some reason this feels incomplete to me. I know one of those proposals enabled something we can't really do now, whereas what I described here of course *can* be done now.
Nov 07 2012
On 2012-11-08 00:43, Adam D. Ruppe wrote:One of the previous threads put forth something like this: template MyAttribute(alias subject, T... arguments) { /* some implementation */ The attribute is a template that replaces the declaration. So you type: [MyAttribute("foo")] class Something {} And the compiler rewrites that to: class __anonymous_Something {} alias Something = MyAttribute!(__anonymous_Something, "foo"); ... or something like that. I'm going off memory here. But then you can use the template to do whatever you'd normally do with a template. For some reason this feels incomplete to me. I know one of those proposals enabled something we can't really do now, whereas what I described here of course *can* be done now.Seems like a poor man's replacement for macro annotations: http://scalamacros.org/future.html -- /Jacob Carlborg
Nov 07 2012
Le 08/11/2012 00:17, Walter Bright a écrit :On 11/7/2012 2:40 PM, deadalnix wrote:The hook is associated to a given attribute so no it doesn't.Java is mostly compile time (and optionally runtime). See http://projectlombok.org/ for what can be done at compile time with attributes + compiler hooks.Doesn't putting compiler hooks in for them make them inherently global?
Nov 07 2012
On 11/7/2012 4:12 PM, deadalnix wrote:Le 08/11/2012 00:17, Walter Bright a écrit :Yes, that makes the attribute global.On 11/7/2012 2:40 PM, deadalnix wrote:The hook is associated to a given attribute so no it doesn't.Java is mostly compile time (and optionally runtime). See http://projectlombok.org/ for what can be done at compile time with attributes + compiler hooks.Doesn't putting compiler hooks in for them make them inherently global?
Nov 07 2012
On 2012-11-08 02:49, Walter Bright wrote:Yes, that makes the attribute global.I don't actually know how this works in Java but if you are forced to use the fully qualified name for the attribute it won't make the attribute global. -- /Jacob Carlborg
Nov 07 2012
On 11/7/2012 11:27 PM, Jacob Carlborg wrote:On 2012-11-08 02:49, Walter Bright wrote:A plugin would apply globally, wouldn't it?Yes, that makes the attribute global.I don't actually know how this works in Java but if you are forced to use the fully qualified name for the attribute it won't make the attribute global.
Nov 08 2012
On 2012-11-08 11:56, Walter Bright wrote:A plugin would apply globally, wouldn't it?Yes, but that wouldn't make the attribute global. I just had a quick look on the Annotation Processing Tool (APT) available in Java. This tool will run an annotation processor over some specified Java files. It will then generate a new set of files with the result of the annotation process. In the annotation processor you have to specify what annotations you want to process. You can either specify you want to process all annotations, "*", or a single annotation, "foo.bar.Baz". http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html -- /Jacob Carlborg
Nov 08 2012
On 11/8/2012 4:37 AM, Jacob Carlborg wrote:On 2012-11-08 11:56, Walter Bright wrote:I believe that does have the essential effect of making the attribute global.A plugin would apply globally, wouldn't it?Yes, but that wouldn't make the attribute global. I just had a quick look on the Annotation Processing Tool (APT) available in Java. This tool will run an annotation processor over some specified Java files. It will then generate a new set of files with the result of the annotation process. In the annotation processor you have to specify what annotations you want to process. You can either specify you want to process all annotations, "*", or a single annotation, "foo.bar.Baz". http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html
Nov 08 2012
On 2012-11-08 20:39, Walter Bright wrote:I believe that does have the essential effect of making the attribute global.I don't understand how. -- /Jacob Carlborg
Nov 08 2012
On 11/8/2012 12:00 PM, Jacob Carlborg wrote:On 2012-11-08 20:39, Walter Bright wrote:Because plugins are a global thing. If you have a plugin that deals with attribute 'X', then you cannot have two plugins that interpret 'X' differently, i.e. 'X' becomes, for all practical purposes, global.I believe that does have the essential effect of making the attribute global.I don't understand how.
Nov 08 2012
On 2012-11-08 23:31, Walter Bright wrote:Because plugins are a global thing. If you have a plugin that deals with attribute 'X', then you cannot have two plugins that interpret 'X' differently, i.e. 'X' becomes, for all practical purposes, global.Well, 'X' is supposed to be the fully qualified name. Can I have my own symbol named std.algorithm.filter and use it together with the std.algorithm.filter function in Phobos? -- /Jacob Carlborg
Nov 08 2012
Le 08/11/2012 11:56, Walter Bright a écrit :On 11/7/2012 11:27 PM, Jacob Carlborg wrote:No it would apply on symbols qualified with a given attribute (provided by the plugin).On 2012-11-08 02:49, Walter Bright wrote:A plugin would apply globally, wouldn't it?Yes, that makes the attribute global.I don't actually know how this works in Java but if you are forced to use the fully qualified name for the attribute it won't make the attribute global.
Nov 09 2012
On 11/9/2012 6:28 PM, deadalnix wrote:Le 08/11/2012 11:56, Walter Bright a écrit :Meaning a given attribute can have only one, global, meaning.On 11/7/2012 11:27 PM, Jacob Carlborg wrote:No it would apply on symbols qualified with a given attribute (provided by the plugin).On 2012-11-08 02:49, Walter Bright wrote:A plugin would apply globally, wouldn't it?Yes, that makes the attribute global.I don't actually know how this works in Java but if you are forced to use the fully qualified name for the attribute it won't make the attribute global.
Nov 09 2012
On 2012-11-10 05:02, Walter Bright wrote:Meaning a given attribute can have only one, global, meaning.Isn't that true for any symbol. Can I have two std.stdio.writeln symbols in the same application? -- /Jacob Carlborg
Nov 10 2012
On 11/10/2012 1:59 AM, Jacob Carlborg wrote:On 2012-11-10 05:02, Walter Bright wrote:Think of it this way. If I have myString.String, and use the strings in it as an attribute in one module, and in another use module use myString.String as an attribute with a totally different meaning, that will not work if plugins are used.Meaning a given attribute can have only one, global, meaning.Isn't that true for any symbol. Can I have two std.stdio.writeln symbols in the same application?
Nov 10 2012
On 2012-11-10 20:04, Walter Bright wrote:Think of it this way. If I have myString.String, and use the strings in it as an attribute in one module, and in another use module use myString.String as an attribute with a totally different meaning, that will not work if plugins are used.I'm not entirely sure what you're meaning here but if you have two symbols with the same name in two different modules their fully qualified names won't be the same. If you're referring to using a string literal as an attribute then that would be a bad thing, like we have tried to explain. It's better to use a type which will have a unique name. If I have misunderstood what you're meaning could you provide a code example? -- /Jacob Carlborg
Nov 10 2012
On 11/10/2012 11:15 AM, Jacob Carlborg wrote:On 2012-11-10 20:04, Walter Bright wrote:That is what I mean, and it also applies to a library type which different modules may press into service as attributes.Think of it this way. If I have myString.String, and use the strings in it as an attribute in one module, and in another use module use myString.String as an attribute with a totally different meaning, that will not work if plugins are used.I'm not entirely sure what you're meaning here but if you have two symbols with the same name in two different modules their fully qualified names won't be the same. If you're referring to using a string literal as an attribute then that would be a bad thing, like we have tried to explain. It's better to use a type which will have a unique name. If I have misunderstood what you're meaning could you provide a code example?
Nov 13 2012
On 2012-11-13 23:24, Walter Bright wrote:That is what I mean, and it also applies to a library type which different modules may press into service as attributes.I think there must be some kind of misunderstanding here. I still don't see the problem if fully qualified symbols are used. I mean, it will be unique. -- /Jacob Carlborg
Nov 13 2012
On 11/13/2012 11:16 PM, Jacob Carlborg wrote:On 2012-11-13 23:24, Walter Bright wrote:We agree that strings can be used globally as attributes with different meanings, right? So why can't test.foo.bar also be used globally as an attribute with different meanings? It's just a type name, it has no magic property that says it cannot be used for different purposes. Ok, let's call it: std.mytypes.mystring ? Now have those string contents mean different things to different users of std.mytypes.mystring.That is what I mean, and it also applies to a library type which different modules may press into service as attributes.I think there must be some kind of misunderstanding here. I still don't see the problem if fully qualified symbols are used. I mean, it will be unique.
Nov 13 2012
On 2012-11-14 08:46, Walter Bright wrote:We agree that strings can be used globally as attributes with different meanings, right?Yes, but I would consider that a bad idea.So why can't test.foo.bar also be used globally as an attribute with different meanings? It's just a type name, it has no magic property that says it cannot be used for different purposes.I guess it could. But there is no way of preventing the user from doing stupid things. I can create a map container out of two arrays, but that's not how arrays are intended to be used.Ok, let's call it: std.mytypes.mystring ? Now have those string contents mean different things to different users of std.mytypes.mystring.If "std.mytypes.mystring" is a variable of the type "string" then the fully qualified name is lost if it's used as an attribute. Something like this: [std.mytypes.mystring] int a; pragma(msg, __traits(getAttributes, a).stringof); Would result in: ("foo") pragma(msg, typeof(__traits(getAttributes, a)).stringof); Would result in: (string) The name "std.mytypes.mystring" is gone. You have no idea where the string came from, who could have put it there. You would need to put the fully qualified name in the content of the string: module std.mytypes; string mystring = "std.mytypes.mystring"; The whole problem with this is that there is no actual thing called "attribute", there are just symbols with attached values. In most cases I think it's the symbol/type name that is interesting. I imagine many attributes just look like this: attribute struct Serializable {} I would prefer that only user defined types explicitly marked with attribute (or similar) could be used as attributes. And preferably, that they cannot be used for anything else. If only user defined types (and preferably marked with attribute) are allowed then you can know exactly where a given attribute comes from and you can look up the documentation. Sure you cannot prevent anyone from using the attribute with a different meaning then it was intended for. But that's true for many other things in programming as well. -- /Jacob Carlborg
Nov 14 2012
On 11/14/2012 2:53 AM, Jacob Carlborg wrote:If "std.mytypes.mystring" is a variable of the type "string" then the fully qualified name is lost if it's used as an attribute. Something like this:I am having a REALLY hard time making my point here. struct MyString { string s; } Now use MyString as an attribute. No, the name is not lost. Yes, two different modules can use MyString as an attribute, and impute completely different meanings into it. Just because it is not a builtin type does not change anything.
Nov 14 2012
On 11/14/12 1:13 PM, Walter Bright wrote:On 11/14/2012 2:53 AM, Jacob Carlborg wrote:I think a simple way to put this is that attribute name lookup works the same as ordinary symbol lookup. Assuming we did a good job at the latter, the former doesn't introduce any specific issues. AndreiIf "std.mytypes.mystring" is a variable of the type "string" then the fully qualified name is lost if it's used as an attribute. Something like this:I am having a REALLY hard time making my point here. struct MyString { string s; } Now use MyString as an attribute. No, the name is not lost. Yes, two different modules can use MyString as an attribute, and impute completely different meanings into it. Just because it is not a builtin type does not change anything.
Nov 14 2012
On 2012-11-14 23:39, Andrei Alexandrescu wrote:I think a simple way to put this is that attribute name lookup works the same as ordinary symbol lookup. Assuming we did a good job at the latter, the former doesn't introduce any specific issues.Exactly. -- /Jacob Carlborg
Nov 15 2012
On 2012-11-14 22:13, Walter Bright wrote:I am having a REALLY hard time making my point here. struct MyString { string s; } Just because it is not a builtin type does not change anything.Sure you _can_ but it would be quite stupid. With user defined types there is at least some context. With a plain string (or any built in type) it can come from any where and mean anything. The difference is, with a user defined type you know the meaning of the attribute, with a built in type you do not, not in the same way at least. -- /Jacob Carlborg
Nov 15 2012
On 11/15/2012 12:22 AM, Jacob Carlborg wrote:On 2012-11-14 22:13, Walter Bright wrote:The whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.I am having a REALLY hard time making my point here. struct MyString { string s; } Just because it is not a builtin type does not change anything.Sure you _can_ but it would be quite stupid. With user defined types there is at least some context. With a plain string (or any built in type) it can come from any where and mean anything. The difference is, with a user defined type you know the meaning of the attribute, with a built in type you do not, not in the same way at least.
Nov 16 2012
On Friday, 16 November 2012 at 10:41:44 UTC, Walter Bright wrote:The whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.Agree. Imagine we have 3 generic libs/modules... "Optimized CTFE Polygon Primitive Lib", Math, Gfx ... and then the "end user", creates a program. Both Math and Gfx, want to use the optimized Polygon in their modules... [Polygon(...)] struct SpaceShip { } This is just as ambiguous as if you had used a built-in int:s... and it can be solved in the exact same way which I outlined in the other thread.
Nov 16 2012
On Friday, 16 November 2012 at 13:12:34 UTC, Tove wrote:On Friday, 16 November 2012 at 10:41:44 UTC, Walter Bright wrote:I don't think this is a valid argument. I challenge you to find a single real-world use case where an *annotation* would be so complex that this would make any sense at all, yet it would be impossible (or even just less clear) to just use a wrapper type like CollisionShape(Polygon(…)) or RenderBounds(Polygon(…)). DavidThe whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.Agree. Imagine we have 3 generic libs/modules... "Optimized CTFE Polygon Primitive Lib", Math, Gfx ... and then the "end user", creates a program. Both Math and Gfx, want to use the optimized Polygon in their modules... [Polygon(...)] struct SpaceShip { } This is just as ambiguous as if you had used a built-in int:s... and it can be solved in the exact same way which I outlined in the other thread.
Nov 16 2012
On 2012-11-16 11:41, Walter Bright wrote:i don't know what to say anymore. I can only repeat what I've already said. This conversion has clearly gone into circles. -- /Jacob CarlborgSure you _can_ but it would be quite stupid. With user defined types there is at least some context. With a plain string (or any built in type) it can come from any where and mean anything. The difference is, with a user defined type you know the meaning of the attribute, with a built in type you do not, not in the same way at least.The whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.
Nov 16 2012
Le 14/11/2012 22:13, Walter Bright a écrit :On 11/14/2012 2:53 AM, Jacob Carlborg wrote:I seriously feel like I'm in Alice in wonderland here. A type is a meaning associated to data. For instance, char[] is an array of char. Note that you can store pointers, integer, or basically anything in that memory. But you don't, because this type give you information about what in this memory, and storing anything else would be confusing as hell. The same way, I can throw a FileExeption every time a problem occurs in any of my programs. That would be insane, but i CAN do that. Well, the same way, I can subvert attribute in any convoluted way I want to. But that make no sens at all (and I don't expect any codebase using such techniques to become really big). The whole point of attaching data to a symbol via attribute is to provide a meaning attached to that symbol. The meaning is given by the type, like it does everywhere else. Your MyString example or an int is a perfect example of a type that have no meaning. Your argument is just like we shouldn't put any protection near a precipice since people can throw themselves over it anyway. Yeah, but at least, they'll do it on purpose and assume the consequences, and that is a huge win.If "std.mytypes.mystring" is a variable of the type "string" then the fully qualified name is lost if it's used as an attribute. Something like this:I am having a REALLY hard time making my point here. struct MyString { string s; } Now use MyString as an attribute. No, the name is not lost. Yes, two different modules can use MyString as an attribute, and impute completely different meanings into it. Just because it is not a builtin type does not change anything.
Nov 16 2012
Le 10/11/2012 20:04, Walter Bright a écrit :On 11/10/2012 1:59 AM, Jacob Carlborg wrote: > On 2012-11-10 05:02, Walter Bright wrote: > >> Meaning a given attribute can have only one, global, meaning. > > Isn't that true for any symbol. Can I have two std.stdio.writeln symbols in the > same application? > Think of it this way. If I have myString.String, and use the strings in it as an attribute in one module, and in another use module use myString.String as an attribute with a totally different meaning, that will not work if plugins are used.Thinking of it this way don't make any sense. The whole point of an attribute is to tell a library about how to understand your code. If many library uses the same attribute, then it defeat the whole point of having attribute. This is why the discussion about disallowing any type as UDA exists in the first place.
Nov 10 2012
On 11/10/2012 12:21 PM, deadalnix wrote:Thinking of it this way don't make any sense. The whole point of an attribute is to tell a library about how to understand your code. If many library uses the same attribute, then it defeat the whole point of having attribute. This is why the discussion about disallowing any type as UDA exists in the first place.I understand that. I just am not convinced of the scope of this issue, and I am not convinced that a runtime attribute system is that applicable for this case, nor am I convinced that exception handling is that applicable (all for reasons already explained). For another analogy, consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.
Nov 13 2012
Walter Bright:consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.The usage of naked basic types as int and double cause troubles. Haskell programmers avoid some of them defining strong types like this (this syntax also allows you to specify exactly what operations you want to be allowed on this new type, with that "deriving"): newtype Angle = A Double deriving (Eq, Ord, Num, Fractional) Similarly you can also tell apart angles represented in degrees from angles in radians, and avoid some bugs. (It's possible to overdo this idea, and make the code too much fussy and not handy to write, so you have to keep some balance and not use too many new types). A possible D syntax, using std.typecons.Typedef: alias Angle = SubTypedef!(double, Eq, Ord, Num); That equals to: alias Angle = Typedef!(double, Subtype, Eq, Ord, Num); Where Eq, etc, are pre-defined template mixins that implement different operations, like equality, opCmp, etc, that Typedef mixes in. Bye, bearophile
Nov 13 2012
On 11/13/2012 2:55 PM, bearophile wrote:Walter Bright:I know that you can use custom types instead, and have better type checking, etc., and can be a pretty good idea for a lot of use cases. But D does not require that. It's up to the programmer.consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.The usage of naked basic types as int and double cause troubles.
Nov 13 2012
Walter Bright: (I know this sub-discussion is a bit OT, but not too much, and I think it's not wasted time.)But D does not require that. It's up to the programmer.<Oh, but the use of "newtype" is not required in Haskell; programmers are free to use it, or to use normal basic types as Int, Integer, Double, etc. Probably newtype is not that useful in little programs. And even in larger programs it's better to not use it too much. And the use of that "using" in a newtype is not standard Haskell, it's a GHC compiler extension to the language, that you have to ask with a compilation switch or an annotation inside the code. That "using" attached to a newtype allows you to both use a newtype like its base type (like the underlying Int), or to choose where the newtype must not do what its base type is able to do (this technically means what typeclasses it conforms to or not). I think D Typedef should allow something similar, despite D has no typeclasses. As an example, currently D Typedef is kind of useless if you want to use it to define a new array type. Bye, bearophile
Nov 13 2012
On 11/13/2012 5:22 PM, bearophile wrote:As an example, currently D Typedef is kind of useless if you want to use it to define a new array type.D's typedef is deprecated, as nobody could figure out what it was good for or properly define its semantics.
Nov 13 2012
Walter Bright:D's typedef is deprecated, as nobody could figure out what it was good for or properly define its semantics.Look better, in both my last posts "Typedef" was std.typecons.Typedef. Bye, bearophile
Nov 13 2012
Walter Bright, el 13 de November a las 16:49 me escribiste:On 11/13/2012 2:55 PM, bearophile wrote:What really amazes me is how you always defend the "will not be included until real uses cases can be shown" and in this case you are doing the exact opposite. Can you provide any real uses cases instead of talking about a completely theoretical and hypothetical cases? Can you provide one concrete case where it makes sense NOT to restrict UDAs to types and it's different from restricting exception to classes derived from Exception? Thank you. --Walter Bright:I know that you can use custom types instead, and have better type checking, etc., and can be a pretty good idea for a lot of use cases. But D does not require that. It's up to the programmer.consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.The usage of naked basic types as int and double cause troubles.
Nov 14 2012
On Wednesday, 14 November 2012 at 11:08:04 UTC, Leandro Lucarella wrote:Can you provide one concrete case where it makes sense NOT to restrict UDAs to types and it's different from restricting exception to classes derived from Exception? Thank you.There was the example with Thrift... struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) } You could use a user defined type for the struct... but for the members it would make sense to use the native type directly... and if you traverse the annotation in sequence rather than as standalone entities.. it's perfectly safe to use 1,2,3 as annotation... i.e. first scan for the Thrift symbol, then scan for native typed int:s...
Nov 14 2012
On 2012-11-14 12:18, Tove wrote:On Wednesday, 14 November 2012 at 11:08:04 UTC, Leandro Lucarella wrote:I assume you mean something like: struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; } In that case I would much rather prefer this: struct UserProfile { Id(1) i32 uid; Id(2) string name; Id(3) string blurb; } Where Id is "thrift.attributes.Id" or something similar. -- /Jacob CarlborgCan you provide one concrete case where it makes sense NOT to restrict UDAs to types and it's different from restricting exception to classes derived from Exception? Thank you.There was the example with Thrift... struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) } You could use a user defined type for the struct... but for the members it would make sense to use the native type directly... and if you traverse the annotation in sequence rather than as standalone entities.. it's perfectly safe to use 1,2,3 as annotation... i.e. first scan for the Thrift symbol, then scan for native typed int:s...
Nov 14 2012
On Wednesday, 14 November 2012 at 12:33:58 UTC, Jacob Carlborg wrote:I assume you mean something like: struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; } In that case I would much rather prefer this: struct UserProfile { Id(1) i32 uid; Id(2) string name; Id(3) string blurb; } Where Id is "thrift.attributes.Id" or something similar.well, similar... but beginning with a symbol... [thrift.attributes.Definition] struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; }
Nov 14 2012
Tove, el 14 de November a las 13:55 me escribiste:OK, that's just a good example of convenience of allowing native types, but I think it is still potentially harmful. What if you pass that struct to another library that have another meaning attached to int annotations? How could you tell that library that this particular int annotations is not for it? I mean, it convenient to be able to throw numbers or strings too: void f() { throw 1; } void g() { throw "error"; } int main() { try { g(); } catch (char[] e) { writefln(e); } try { f(); } catch (int i) { return i; } return 0; } --struct UserProfile { Id(1) i32 uid; Id(2) string name; Id(3) string blurb; } Where Id is "thrift.attributes.Id" or something similar.well, similar... but beginning with a symbol... [thrift.attributes.Definition] struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; }
Nov 14 2012
On 11/14/2012 03:31 PM, Leandro Lucarella wrote:Tove, el 14 de November a las 13:55 me escribiste:By not telling it that they are for it. Note that the [thrift.attributes.Definition] annotation is significant.OK, that's just a good example of convenience of allowing native types, but I think it is still potentially harmful. What if you pass that struct to another library that have another meaning attached to int annotations? How could you tell that library that this particular int annotations is not for it? ...struct UserProfile { Id(1) i32 uid; Id(2) string name; Id(3) string blurb; } Where Id is "thrift.attributes.Id" or something similar.well, similar... but beginning with a symbol... [thrift.attributes.Definition] struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; }I mean, it convenient to be able to throw numbers or strings too: void f() { throw 1; } void g() { throw "error"; } int main() { try { g(); } catch (char[] e) { writefln(e); } try { f(); } catch (int i) { return i; } return 0; }What he does is more like (but not exactly like): class ThriftException{ int x; this(int x){ this.x = x; } }
Nov 14 2012
Timon Gehr, el 14 de November a las 17:25 me escribiste:On 11/14/2012 03:31 PM, Leandro Lucarella wrote:Yes, but that only tells thrift how to interpret those ints, it doesn't tell any other module they *shouldn't* interpret them. Or are you suggesting every module that want to attach meaning to an int attribute should check if the parent module doesn't have any other attribute attached to it?Tove, el 14 de November a las 13:55 me escribiste:By not telling it that they are for it. Note that the [thrift.attributes.Definition] annotation is significant.OK, that's just a good example of convenience of allowing native types, but I think it is still potentially harmful. What if you pass that struct to another library that have another meaning attached to int annotations? How could you tell that library that this particular int annotations is not for it? ...struct UserProfile { Id(1) i32 uid; Id(2) string name; Id(3) string blurb; } Where Id is "thrift.attributes.Id" or something similar.well, similar... but beginning with a symbol... [thrift.attributes.Definition] struct UserProfile { [1] i32 uid; [2] string name; [3] string blurb; }I don't know what does this mean. --I mean, it convenient to be able to throw numbers or strings too: void f() { throw 1; } void g() { throw "error"; } int main() { try { g(); } catch (char[] e) { writefln(e); } try { f(); } catch (int i) { return i; } return 0; }What he does is more like (but not exactly like): class ThriftException{ int x; this(int x){ this.x = x; } }
Nov 15 2012
On Wednesday, 14 November 2012 at 11:18:28 UTC, Tove wrote:There was the example with Thrift... struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) } You could use a user defined type for the struct... but for the members it would make sense to use the native type directly... and if you traverse the annotation in sequence rather than as standalone entities.. it's perfectly safe to use 1,2,3 as annotation...But what if you want to use that struct with another library as well, for which you might also want to tack some ids on the fields? I'm the author of the current D implementation in Thrift, and if/when user defined attributes become stable and I'll amend it to take advantage of UDAs, I'll definitely not go for raw literals… David
Nov 14 2012
On Wednesday, 14 November 2012 at 13:03:18 UTC, David Nadlinger wrote:On Wednesday, 14 November 2012 at 11:18:28 UTC, Tove wrote:// in this nested scope, all uints are interpreted as belonging to the thrift module. [std.attributes(uint, thrift)] struct UserProfile ... // error detected at compile-time [std.attributes(uint, thrift), std.attributes(uint, thrift2)] struct UserProfile ...There was the example with Thrift... struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) } You could use a user defined type for the struct... but for the members it would make sense to use the native type directly... and if you traverse the annotation in sequence rather than as standalone entities.. it's perfectly safe to use 1,2,3 as annotation...But what if you want to use that struct with another library as well, for which you might also want to tack some ids on the fields? I'm the author of the current D implementation in Thrift, and if/when user defined attributes become stable and I'll amend it to take advantage of UDAs, I'll definitely not go for raw literals… David
Nov 14 2012
On 2012-11-14 14:28, Tove wrote:// in this nested scope, all uints are interpreted as belonging to the thrift module. [std.attributes(uint, thrift)] struct UserProfile ... // error detected at compile-time [std.attributes(uint, thrift), std.attributes(uint, thrift2)] struct UserProfile ...That doesn't sound like a very good idea. I think it's better to not use raw ints. -- /Jacob Carlborg
Nov 14 2012
On Wednesday, 14 November 2012 at 13:28:05 UTC, Tove wrote:// in this nested scope, all uints are interpreted as belonging to the thrift module. [std.attributes(uint, thrift)] struct UserProfile ... // error detected at compile-time [std.attributes(uint, thrift), std.attributes(uint, thrift2)] struct UserProfile ...»interpreted as belonging to the thrift module« – what do you even mean by that? As of now, UDAs are just a way to tuck arbitrary symbols onto declarations. There is no concept of »belonging« to a module, and I don't think there should be. Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type? David
Nov 14 2012
On Wednesday, 14 November 2012 at 13:28:05 UTC, Tove wrote:// in this nested scope, all uints are interpreted as belonging to the thrift module. [std.attributes(uint, thrift)] struct UserProfile ... // error detected at compile-time [std.attributes(uint, thrift), std.attributes(uint, thrift2)] struct UserProfile ...»interpreted as belonging to the thrift module« – what do you even mean by that? As of now, UDAs are just a way to tuck arbitrary symbols onto declarations. There is no concept of »belonging« to a module, and I don't think there should be. Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type? David
Nov 14 2012
On Wednesday, 14 November 2012 at 13:28:05 UTC, Tove wrote:// in this nested scope, all uints are interpreted as belonging to the thrift module. [std.attributes(uint, thrift)] struct UserProfile ... // error detected at compile-time [std.attributes(uint, thrift), std.attributes(uint, thrift2)] struct UserProfile ...»interpreted as belonging to the thrift module« – what do you even mean by that? As of now, UDAs are just a way to tuck arbitrary symbols onto declarations. There is no concept of »belonging« to a module, and I don't think there should be. Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type? David
Nov 14 2012
On Wednesday, 14 November 2012 at 23:57:38 UTC, David Nadlinger wrote:Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type? DavidI disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.
Nov 15 2012
On Thursday, 15 November 2012 at 08:45:49 UTC, Tove wrote:I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.You are missing the point: In your proposal, if you want to use two libraries together which are expecting you to provide e.g. 'int' annotations, you are screwed. This is a big, BIG problem. David
Nov 15 2012
On Thursday, 15 November 2012 at 22:04:27 UTC, David Nadlinger wrote:On Thursday, 15 November 2012 at 08:45:49 UTC, Tove wrote:no, I implied the solution already... actually there are many different ways to solve it... some possible today, some require new minor support features(like sending the annotated symbol as a template alias parameter to the annotation)... but could give us compile time errors when ambiguity is detected. In the common case there are no collisions, so most of the time we can use the nice user-friendly syntax! [lib1.x] struct User { [1] int uid; } But we _can_ disambiguate when needed... [lib1.x, lib2.y] struct User { [lib!1, lib2!2] int uid; // ok [1, lib2!2] int uid; // ok [lib1!1, 2] int uid; // ok [1,2] int uid; // not supported [1] int uid; // not supported } lib2 doesn't have to know about lib1. lib1 doesn't have to know about lib2. Because they just have to check the annotation in _prioritized_ order. 1. find my unique lib2.y symbol 2. if there is a lib2!uint on a nested symbol, use it... 3. if not check for a native int.I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.You are missing the point: In your proposal, if you want to use two libraries together which are expecting you to provide e.g. 'int' annotations, you are screwed. This is a big, BIG problem. David
Nov 16 2012
On 11/14/2012 2:18 AM, Leandro Lucarella wrote:Can you provide one concrete case where it makes sense NOT to restrict UDAs to typesOne where its use is entirely inside the scope of a module, i.e. local use of it. There seems to be an assumption that UDAs are global, but I don't see a reason why that should always be true.and it's different from restricting exception to classes derived from Exception?Exceptions leak out of their scopes as an explicit part of their nature. That's the whole point of them, and I think that's the fundamental difference.
Nov 16 2012
Le 13/11/2012 23:27, Walter Bright a écrit :On 11/10/2012 12:21 PM, deadalnix wrote:I presented you compile time uses cases for such a mecanism already. See project lombok for instance.Thinking of it this way don't make any sense. The whole point of an attribute is to tell a library about how to understand your code. If many library uses the same attribute, then it defeat the whole point of having attribute. This is why the discussion about disallowing any type as UDA exists in the first place.I understand that. I just am not convinced of the scope of this issue, and I am not convinced that a runtime attribute system is that applicable for this case, nor am I convinced that exception handling is that applicable (all for reasons already explained).For another analogy, consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.int isn't meant to be discovered. The whole point of attribute is to be discovered.
Nov 13 2012
Le 10/11/2012 05:02, Walter Bright a écrit :On 11/9/2012 6:28 PM, deadalnix wrote:Yes, it have to. What is the point of attaching an attribute is you cannot know what meaning it has ? If an attribute can have ambiguous meaning, then it defeat the whole point of having attribute.Le 08/11/2012 11:56, Walter Bright a écrit :Meaning a given attribute can have only one, global, meaning.On 11/7/2012 11:27 PM, Jacob Carlborg wrote:No it would apply on symbols qualified with a given attribute (provided by the plugin).On 2012-11-08 02:49, Walter Bright wrote:A plugin would apply globally, wouldn't it?Yes, that makes the attribute global.I don't actually know how this works in Java but if you are forced to use the fully qualified name for the attribute it won't make the attribute global.
Nov 10 2012
started a new thread on this over in digitalmars.D
Nov 07 2012
On 2012-11-07 23:20, Walter Bright wrote:There's another aspect to this. D's UDAs are a purely compile time system, attaching arbitrary metadata to specific symbols. The other UDA systems I'm aware of appear to be runtime systems. This implies the use cases will be different - how, I don't really know. But I don't know of any other compile time UDA system. Experience with runtime systems may not be as applicable. Another interesting data point is CTFE. C++11 has CTFE, but it was deliberately crippled and burdened with "constexpr". From what I read, this was out of fear that it would turn out to be an overused and overabused feature. Of course, this turned out to be a large error. One last thing. Sure, string attributes can (and surely would be) used for different purposes in different libraries. The presumption is that this would cause a conflict. But would it? There are two aspects to a UDA - the attribute itself, and the symbol it is attached to. In order to get the UDA for a symbol, one has to look up the symbol.This is what I start to like less and less about the current implementation of UDA. There is no actual attribute. There is the symbol with a bunch of random attached values. I want to be able to do something like this: module bar; attribute struct foo { string name; } foo int a; alias Tuple!(__traits(getAttributes, foo)) TP; enum bool yes = hasAttribute!(bar.foo); static if (yes) enum foo attr = getAttribute!(bar.foo); The last two could actually be library functions.There isn't a global repository of symbols in D. You'd have to say "I want to look in module X for symbols." Why would you look in module X for an attribute that you have no reason to believe applies to symbols from X? How would an attribute for module X's symbols leak out of X on their own?Have you ever heard of libraries. You can pass a symbol as an alias parameter to a function of a completely different library.It's not quite analogous to exceptions, because arbitrary exceptions thrown from module X can flow through your code even though you have no idea module X even exists.-- /Jacob Carlborg
Nov 07 2012
On Thursday, 8 November 2012 at 07:35:30 UTC, Jacob Carlborg wrote:On 2012-11-07 23:20, Walter Bright wrote: module bar; attribute struct foo { string name; } foo int a; alias Tuple!(__traits(getAttributes, foo)) TP; enum bool yes = hasAttribute!(bar.foo); static if (yes) enum foo attr = getAttribute!(bar.foo); The last two could actually be library functions.Could you explain why it is impossible without complicating the current state of things? I gave it a quick try and it seems to work reasonably well (a proper implementation will be more involved due to compiler bugs and language issues irrelevant to this discussion): // library that defines attribute accessors module library; import std.typetuple; template TypeOf(alias symbol) { alias typeof(symbol) TypeOf; } template indexOfAttribute(alias symbol, alias attrType) { alias staticMap!(TypeOf, __traits(getAttributes, symbol)) attrTypes; enum indexOfAttribute = staticIndexOf!(attrTypes, attrType); } template hasAttribute(alias symbol, alias attrType) { enum hasAttribute = indexOfAttribute!(symbol, attrType) != -1; } template getAttribute(alias symbol, alias attrType) { alias TypeTuple!(__traits(getAttributes, symbol)) attrs; enum getAttribute = attrs[indexOfAttribute!(symbol, attrType)]; } // module that defines a foo attribute module a; struct foo { string name; } [foo("a's foo")] int a; // an unrelated module that defines its own foo module b; import library; import a; struct foo { string name; } [foo("b's foo")] int b; static if (hasAttribute!(b, foo)) { alias getAttribute!(b, foo) t; static assert(getAttribute!(b, foo).name == "b's foo"); } static if (hasAttribute!(a.a, a.foo)) static assert(getAttribute!(a.a, a.foo).name == "a's foo"); void main() { }
Nov 08 2012
On Thursday, 8 November 2012 at 09:08:23 UTC, Max Samukha wrote:alias getAttribute!(b, foo) t;Ignore that line.
Nov 08 2012
On 2012-11-08 10:08, Max Samukha wrote:Could you explain why it is impossible without complicating the current state of things? I gave it a quick try and it seems to work reasonably well (a proper implementation will be more involved due to compiler bugs and language issues irrelevant to this discussion):I just see no point in allowing random structs and classes acting like attributes. Suddenly someone starts to use your struct as an attribute without you having any intention of it acting like an attribute and you don't know about it. -- /Jacob Carlborg
Nov 08 2012
On Thursday, 8 November 2012 at 12:42:38 UTC, Jacob Carlborg wrote:On 2012-11-08 10:08, Max Samukha wrote:The problem is where to draw the line. There is nothing to stop an idiot programmer from applying your attributes to a wrong target, so we'd better take care of that by introducing those target-restricting attributes specially treated by the compiler. Instead of throwing attributes on attributes, I'd rather have decorators based on templates as someone proposed. Those would allow the programmer to implement arbitrary restrictions on their usage.Could you explain why it is impossible without complicating the current state of things? I gave it a quick try and it seems to work reasonably well (a proper implementation will be more involved due to compiler bugs and language issues irrelevant to this discussion):I just see no point in allowing random structs and classes acting like attributes. Suddenly someone starts to use your struct as an attribute without you having any intention of it acting like an attribute and you don't know about it.
Nov 08 2012
On 2012-11-08 19:03, Max Samukha wrote:The problem is where to draw the line. There is nothing to stop an idiot programmer from applying your attributes to a wrong target, so we'd better take care of that by introducing those target-restricting attributes specially treated by the compiler.Sure, but we don't want to have a comment for every struct indented as an attribute saying "this is an attribute". We do have "const", "pure", "nothrow" and so on for a reason. We want the compiler to be able to force/validate our intent and not have to write the intention in the documentation. -- /Jacob Carlborg
Nov 08 2012
On 11/8/12 12:20 AM, Walter Bright wrote:One last thing. Sure, string attributes can (and surely would be) used for different purposes in different libraries. The presumption is that this would cause a conflict. But would it? There are two aspects to a UDA - the attribute itself, and the symbol it is attached to. In order to get the UDA for a symbol, one has to look up the symbol. There isn't a global repository of symbols in D. You'd have to say "I want to look in module X for symbols." Why would you look in module X for an attribute that you have no reason to believe applies to symbols from X? How would an attribute for module X's symbols leak out of X on their own?Actually there's a stark difference between string attributes and symbol attributes (assuming I understand the point): attribute lookup and potential ambiguity are solved using regular symbol lookup and potential ambiguity - by using name resolution. In contrast, string attributes have no other resolution mechanism than string comparison. So now say two modules moda and modb define an attribute "untainted" with distinct semantics. If "untainted" is a string, there's no way out of this - the modules simply cannot work together. In contrast, if untainted is a regular symbol, it will cause ambiguity errors that are solvable by using qualified lookup a la moda.untainted and modb.untainted. Andrei
Nov 08 2012
Le 07/11/2012 05:19, Walter Bright a écrit :On 11/6/2012 7:52 PM, bearophile wrote:I don't think that is a good idea. As attribute as they are defined agglomerate in a tuple, without correct typing, it is impossible to determine for a piece of code which attributes belongs to the current processing or not. For instance, let say that I'm writing a lib using attributes. I expect int attribute to be attached to a symbol and does some processing on it. If another dev of another lib decide to do the same, then it is is now impossible to use both libs together. Unless we decide up front, by convention, what an int attribute means. But even in this case, it is risky. As my experience shown in the past, using convention to ensure certain property in the some code usually fail.Walter Bright:D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.But I'm not sure at this point if that is the right thing to do.Why?[If you decide to restrict UDAs, then later it will be easy to extend them, it will not break code. While doing the opposite break code. It's you the one that has taught me to design things this way :-) ]It's a good point, but I have no experience with UDAs. There may be emergent behavior with these features that is completely unexpected, and we wouldn't find out about it without having it there.Yes, I know it's a risk. (And it was a no-brainer to restrict the exception types. But one must be careful in drawing analogies in programming, as different things are, well, different and can be different in unexpected, surprising ways.)
Nov 07 2012
"Walter Bright" <newshound2 digitalmars.com> wrote in message news:k7cko9$hes$1 digitalmars.com...On 11/6/2012 6:10 PM, Daniel Murphy wrote:I don't know if it will turn out to be useful either. But if it's left in there, right or wrong, people will use it and it will be impossible to remove later. If two libraries both use string literal annotations for metadata (and they will) you can no longer use both on the same declaration at once. This leads back to C/C++'s global namespace. As an example: [3] class Blah {} What on earth is 3? Why would you want to attach 3 to a class declaration? How many different ways are there for libraries to interpret this? Most importantly, if users still want to experiment with anonymous annotations, they still can: [tuple(3)] class Blah {} Adding speculative features with no use case in mind is a recipe for disaster. Much like how you can use extern(C) to force global visibility, you can still get the less hygienic behaviour, if you explicitly ask for it. We lose nothing. If it turns out this was the wrong call, built-in types can be restored without breaking a single line of code.My thoughts exactly. It reminds me of the horror of C++ exceptions. I think it would be reasonable to require every annotation is a struct or class.Good analogy. But I'm not sure at this point if that is the right thing to do.
Nov 06 2012
On 11/07/2012 08:08 AM, Daniel Murphy wrote:"Walter Bright" <newshound2 digitalmars.com> wrote in message news:k7cko9$hes$1 digitalmars.com...Then what does this particular restriction buy?On 11/6/2012 6:10 PM, Daniel Murphy wrote:I don't know if it will turn out to be useful either. But if it's left in there, right or wrong, people will use it and it will be impossible to remove later. If two libraries both use string literal annotations for metadata (and they will) you can no longer use both on the same declaration at once. This leads back to C/C++'s global namespace. As an example: [3] class Blah {} What on earth is 3? Why would you want to attach 3 to a class declaration? How many different ways are there for libraries to interpret this? Most importantly, if users still want to experiment with anonymous annotations, they still can: [tuple(3)] class Blah {}My thoughts exactly. It reminds me of the horror of C++ exceptions. I think it would be reasonable to require every annotation is a struct or class.Good analogy. But I'm not sure at this point if that is the right thing to do.Adding speculative features with no use case in mind is a recipe for disaster. Much like how you can use extern(C) to force global visibility, you can still get the less hygienic behaviour, if you explicitly ask for it. We lose nothing. If it turns out this was the wrong call, built-in types can be restored without breaking a single line of code.That is never a given in D. static assert(!is(typeof({struct S{ [2] int x; }})));
Nov 07 2012
Le 07/11/2012 10:13, Timon Gehr a écrit :On 11/07/2012 08:08 AM, Daniel Murphy wrote:I'd argue that is expression is the problem here, not really the annotation."Walter Bright" <newshound2 digitalmars.com> wrote in message news:k7cko9$hes$1 digitalmars.com...Then what does this particular restriction buy?On 11/6/2012 6:10 PM, Daniel Murphy wrote:I don't know if it will turn out to be useful either. But if it's left in there, right or wrong, people will use it and it will be impossible to remove later. If two libraries both use string literal annotations for metadata (and they will) you can no longer use both on the same declaration at once. This leads back to C/C++'s global namespace. As an example: [3] class Blah {} What on earth is 3? Why would you want to attach 3 to a class declaration? How many different ways are there for libraries to interpret this? Most importantly, if users still want to experiment with anonymous annotations, they still can: [tuple(3)] class Blah {}My thoughts exactly. It reminds me of the horror of C++ exceptions. I think it would be reasonable to require every annotation is a struct or class.Good analogy. But I'm not sure at this point if that is the right thing to do.Adding speculative features with no use case in mind is a recipe for disaster. Much like how you can use extern(C) to force global visibility, you can still get the less hygienic behaviour, if you explicitly ask for it. We lose nothing. If it turns out this was the wrong call, built-in types can be restored without breaking a single line of code.That is never a given in D. static assert(!is(typeof({struct S{ [2] int x; }})));
Nov 07 2012
"Timon Gehr" <timon.gehr gmx.ch> wrote in message news:k7d8n1$1o69$1 digitalmars.com...It makes it harder to do the wrong thing.Most importantly, if users still want to experiment with anonymous annotations, they still can: [tuple(3)] class Blah {}Then what does this particular restriction buy?
Nov 07 2012
On 2012-39-06 20:11, Jacob Carlborg <doob me.com> wrote:On 2012-11-06 19:24, David Nadlinger wrote:ly =You are right, UDAs must definitely leverage D's module system for encapsulation/disambiguation. Use of string literals (which are intrinsically =C2=BBglobal=C2=AB) as annotations needs to be explicit=Because string literals are just a special case of literals? i.e. if this works: struct MyString { string s; alias s this; } MyString("Foo") int n; then why should this not work: "Foo" int n; I agree it's useless, but it seems a very arbitrary restriction, too. -- = Simendiscouraged.Then why allow it in the first place?
Nov 07 2012
On 2012-11-07 10:06, Simen Kjaeraas wrote:Because string literals are just a special case of literals? i.e. if this works: struct MyString { string s; alias s this; } MyString("Foo") int n; then why should this not work: "Foo" int n; I agree it's useless, but it seems a very arbitrary restriction, too.That's why I'm starting to think we need to declare an attribute, see my other post: http://forum.dlang.org/thread/k7bbsu$11ls$1 digitalmars.com#post-k7dijh:242ast:241:40digitalmars.com -- /Jacob Carlborg
Nov 07 2012
Le 06/11/2012 09:20, Sönke Ludwig a écrit :Wow, that's a surprise! Just yesterday I was thinking that it would be really nice to have them for a piece of code ;) But shouldn't we keep the syntax closer to normal attributes and other languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff). (*) i.e. mytype or ("string") and without the '[]'+1 In addition, this is [] thing will require lookahead when parsing to detect if we have an expression (array literal) or a declaration.
Nov 06 2012
On 11/6/2012 8:29 AM, deadalnix wrote:In addition, this is [] thing will require lookahead when parsing to detect if we have an expression (array literal) or a declaration.Not really, as an array literal starting an expression is kinda meaningless, like: a*b; is a declaration, not a multiply.
Nov 06 2012
Le 06/11/2012 17:37, Walter Bright a écrit :On 11/6/2012 8:29 AM, deadalnix wrote:Not with UFCS.In addition, this is [] thing will require lookahead when parsing to detect if we have an expression (array literal) or a declaration.Not really, as an array literal starting an expression is kinda meaningless,
Nov 06 2012
On 11/6/2012 9:01 AM, deadalnix wrote:Le 06/11/2012 17:37, Walter Bright a écrit :You have a point.On 11/6/2012 8:29 AM, deadalnix wrote:Not with UFCS.In addition, this is [] thing will require lookahead when parsing to detect if we have an expression (array literal) or a declaration.Not really, as an array literal starting an expression is kinda meaningless,
Nov 06 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:-snip-It doesn't look like it would be possible to schedule any runtime code using this, meaning they're not usable for stuff like registering types for serialization support, or doing runtime linking when attached to a function pointer, etc. Even with user defined types or functions used in the attribute, the type or function itself doesn't know anything about the symbol it is being attached to, so it's quite limited what it can do. this one is extremely limiting due to the two above points. I'd love to hear some examples of what this particular take on UDAs allows in D, though.
Nov 06 2012
On 11/6/2012 12:39 AM, Jakob Ovrum wrote:> On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:Since D allows one to inquire and get a list of symbols, one can then iterate over them at compile time to determine which are serializable (or have some other specific attribute).-snip-It doesn't look like it would be possible to schedule any runtime code using this, meaning they're not usable for stuff like registering types for serialization support, or doing runtime linking when attached to a function pointer, etc.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:42:44 UTC, Walter Bright wrote:Since D allows one to inquire and get a list of symbols, one can then iterate over them at compile time to determine which are serializable (or have some other specific attribute).Yes, but somewhere you have to put startup code pointing in the general direction of where the attributes are used (like a module), it's not automatic. A static constructor cannot be used because it has no idea where to look. But, I yield until someone comes up with actual examples of how these UDAs are useful, because I can't think of anything interesting at the moment. I guess I should go read over the old discussions you linked (I remember participating, but can't remember any specifics).
Nov 06 2012
Am 06.11.2012 09:49, schrieb Jakob Ovrum:But, I yield until someone comes up with actual examples of how these UDAs are useful, because I can't think of anything interesting at the moment. I guess I should go read over the old discussions you linked (I remember participating, but can't remember any specifics).you're just to deep catched in the .Net-Everything-Is-Done-In-Runtime-Paradigm - thats all :) most of the stuff .Net does in runtime is not absolutely needed at runtime - but they need to because there is no compiletime reflection system available at all - and that trains developer to always thing in runtime-aspects - always
Nov 06 2012
On Tuesday, 6 November 2012 at 09:03:49 UTC, dennis luehring wrote:you're just to deep catched in the .Net-Everything-Is-Done-In-Runtime-Paradigm - thats all :)No.
Nov 06 2012
Am 06.11.2012 10:04, schrieb Jakob Ovrum:On Tuesday, 6 November 2012 at 09:03:49 UTC, dennis luehring wrote:ok not you - but many othersyou're just to deep catched in the .Net-Everything-Is-Done-In-Runtime-Paradigm - thats all :)No.
Nov 06 2012
Am Tue, 06 Nov 2012 09:49:42 +0100 schrieb "Jakob Ovrum" <jakobovrum gmail.com>:But, I yield until someone comes up with actual examples of how these UDAs are useful, because I can't think of anything interesting at the moment. I guess I should go read over the old discussions you linked (I remember participating, but can't remember any specifics).The std.benchmark proposal currently requires all benchmark functions to be named "benchmark_name": void benchmark_stdio_write_test() {} with UDA: benchmark("stdio write test") void benchStdioWrite(); Of course you still need that "sheduleBenchmarks" mixin in every module and of course it'd be nice to avoid that. But UDAs are already a big step forward.
Nov 06 2012
On 11/6/2012 8:04 AM, Johannes Pfau wrote:> The std.benchmark proposal currently requires all benchmark functions tobe named "benchmark_name": void benchmark_stdio_write_test() {} with UDA: benchmark("stdio write test") void benchStdioWrite(); Of course you still need that "sheduleBenchmarks" mixin in every module and of course it'd be nice to avoid that. But UDAs are already a big step forward.Consider that you can use a tuple generated elsewhere for a UDA: [tp] void foo(); where tp is a tuple. You can even grab the attributes from another symbol, turn them into a tuple, and apply the tuple as an attribute to a new symbol. Tuples can, of course, be sliced and concatenated. In other words, by using tuples, you can "encapsulate" what the attributes expand to in the same way you can change target code by changing the definition of user defined types.
Nov 06 2012
On 2012-11-06 17:22, Walter Bright wrote:Consider that you can use a tuple generated elsewhere for a UDA: [tp] void foo(); where tp is a tuple. You can even grab the attributes from another symbol, turn them into a tuple, and apply the tuple as an attribute to a new symbol. Tuples can, of course, be sliced and concatenated. In other words, by using tuples, you can "encapsulate" what the attributes expand to in the same way you can change target code by changing the definition of user defined types.Then allow something like this: (tp) Or foo(tp) -- /Jacob Carlborg
Nov 06 2012
On 11/6/2012 12:42 AM, Walter Bright wrote:Since D allows one to inquire and get a list of symbols, one can then iterate over them at compile time to determine which are serializable (or have some other specific attribute).To emphasize, the User Defined Attributes thing is completely a compile time feature. However, a user defined runtime system can be built on top of it. It gives the best of both worlds.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:50:32 UTC, Walter Bright wrote:To emphasize, the User Defined Attributes thing is completely a compile time feature. However, a user defined runtime system can be built on top of it. It gives the best of both worlds.Problem is that there's no way to do this without having the user specify which modules it should work for, like: import attributes; import a, b, c; static this() // This code cannot be automated. { initAttributes!a(); initAttributes!b(); initAttributes!c(); }
Nov 06 2012
n 11/6/2012 12:59 AM, Jakob Ovrum wrote:Problem is that there's no way to do this without having the user specify which modules it should work for, like: import attributes; import a, b, c; static this() // This code cannot be automated. { initAttributes!a(); initAttributes!b(); initAttributes!c(); }Is that really a problem?
Nov 06 2012
On Tuesday, 6 November 2012 at 09:07:34 UTC, Walter Bright wrote:Is that really a problem?I don't strictly need it for any of my projects, where I'm already using lazy initialization for these cases. I guess time will tell if it's significant for other applications.
Nov 06 2012
Le 06/11/2012 10:07, Walter Bright a écrit :n 11/6/2012 12:59 AM, Jakob Ovrum wrote: > Problem is that there's no way to do this without having the user specify which > modules it should work for, like: > > import attributes; > import a, b, c; > > static this() // This code cannot be automated. > { > initAttributes!a(); > initAttributes!b(); > initAttributes!c(); > } > Is that really a problem?I'm not sure. How can AOP be implemented on top of that ?
Nov 06 2012
On Tuesday, 6 November 2012 at 08:39:47 UTC, Jakob Ovrum wrote:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:Runtime arrtibutes can be implemented as properties in object.d. This would work for classes only and for other types it can be implemented manually. Runtime attributes require substantial amount of work, introducing bugs, bloating ABI and new questions about how this feature does work with others.-snip-It doesn't look like it would be possible to schedule any runtime code using this, meaning they're not usable for stuff like registering types for serialization support, or doing runtime linking when attached to a function pointer, etc.
Nov 06 2012
On Tuesday, 6 November 2012 at 08:56:26 UTC, Maxim Fomin wrote:Runtime arrtibutes can be implemented as properties in object.d. This would work for classes only and for other types it can be implemented manually. Runtime attributes require substantial amount of work, introducing bugs, bloating ABI and new questions about how this feature does work with others.I'm not suggesting runtime attributes should be part of the language, nor am I suggesting we add them to Phobos. All I'm saying is the UDA system has to be powerful enough that it *could* be implemented in a library if desired.
Nov 06 2012
Am 06.11.2012 09:39, schrieb Jakob Ovrum:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:used can feel a lot like magic, because they can do things on their own. In contrast it feels quite clean to me to simply think of attributes of what the word means - a simple tag on the declaration. Some otherwise possible globally operating applications may not be doable without some boilerplate code. But a lot of stuff, including controlling seralization, interface generation or statically checked custom type constraints should be perfectly possible.-snip-It doesn't look like it would be possible to schedule any runtime code using this, meaning they're not usable for stuff like registering types for serialization support, or doing runtime linking when attached to a function pointer, etc. Even with user defined types or functions used in the attribute, the type or function itself doesn't know anything about the symbol it is being attached to, so it's quite limited what it can do. one is extremely limiting due to the two above points. I'd love to hear some examples of what this particular take on UDAs allows in D, though.
Nov 06 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:snipNice to hear because it was unexpected and was requested prevously by community.
Nov 06 2012
On 11/6/2012 12:49 AM, Maxim Fomin wrote:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:I've been intending to do it for a while now.snipNice to hear because it was unexpected and was requested prevously by community.
Nov 06 2012
On Tuesday, November 06, 2012 01:06:49 Walter Bright wrote:On 11/6/2012 12:49 AM, Maxim Fomin wrote:I always figured that it was pretty much a given that we'd get it at some point but that we'd wait until things were more stable before adding it. But if it was quick and easy to do now, all the better. - Jonathan M DavisOn Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:I've been intending to do it for a while now.snipNice to hear because it was unexpected and was requested prevously by community.
Nov 06 2012
On 11/6/2012 12:47 PM, Jonathan M Davis wrote:I always figured that it was pretty much a given that we'd get it at some point but that we'd wait until things were more stable before adding it. But if it was quick and easy to do now, all the better.Anything I can do to make sure that going back to C++ is too terrible to contemplate <g>. There's also I don't anticipate this being destabilizing. It doesn't affect the rest of the language at all. It doesn't break any existing code, or change any existing rules.
Nov 06 2012
Le 06/11/2012 22:49, Walter Bright a écrit :On 11/6/2012 12:47 PM, Jonathan M Davis wrote:As soon as this is added, code will use it and bugs in that part will soon not be limited to users of that part.I always figured that it was pretty much a given that we'd get it at some point but that we'd wait until things were more stable before adding it. But if it was quick and easy to do now, all the better.Anything I can do to make sure that going back to C++ is too terrible to contemplate <g>. There's also I don't anticipate this being destabilizing. It doesn't affect the rest of the language at all. It doesn't break any existing code, or change any existing rules.
Nov 06 2012
Wow! This is an early christmas gift. Just to be sure. Is the following also possible: ["Serializable"] class Foo { int bar; } This will attach the UDA to the ClassDeclaration. The examples you've shown only attach UDAs to variable declarations. /Jonas
Nov 06 2012
On 11/6/2012 1:06 AM, Jonas Drewsen wrote:Wow! This is an early christmas gift. Just to be sure. Is the following also possible: ["Serializable"] class Foo { int bar; } This will attach the UDA to the ClassDeclaration. The examples you've shown only attach UDAs to variable declarations. /JonasYes, you can attach them to other symbols, including user defined types.
Nov 06 2012
On Tuesday, 6 November 2012 at 09:08:25 UTC, Walter Bright wrote:On 11/6/2012 1:06 AM, Jonas Drewsen wrote:Great. Can't wait to play around with this. I think project Orange could really take advantage of this. /JonasWow! This is an early christmas gift. Just to be sure. Is the following also possible: ["Serializable"] class Foo { int bar; } This will attach the UDA to the ClassDeclaration. The examples you've shown only attach UDAs to variable declarations. /JonasYes, you can attach them to other symbols, including user defined types.
Nov 06 2012
Walter Bright wrote:References: =20 http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_aga=in_163042.html=20 http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_prop=osal_yeah_another_one_163246.html=20 Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor). =20 You can download it here and try it out: =20 http://ftp.digitalmars.com/dmd2beta.zip =20 As a bonus, that beta also can generate Win64 executables, and you can even symbolically debug them with VS! (Thanks to Rainer Sch=C3=BCtze for his invaluable help with that). =20 Here's the rather skimpy and lame spec I banged out: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D==3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3DUser Defined Attributes ----------------------- =20 User Defined Attributes (UDA) are compile time expressions that can be at=tachedto a declaration. These attributes can then be queried, extracted, and ma=nipulatedat compile time. There is no runtime component to them. =20 Grammatically, a UDA is a StorageClass: =20 StorageClass: UserDefinedAttribute =20 UserDefinedAttribute: [ ArgumentList ] =20 And looks like: =20 [ 3 ] int a; [ "string", 7 ]: int b; =20 If there are multiple UDAs in scope for a declaration, they are concatena=ted:=20 [ 1 ] { [ 2 ] int a; // has UDA's [1,2] [ "string" ] int b; // has UDA's [1,"string"] } =20 UDA's can be extracted into an expression tuple using __traits: =20 [ 'c' ] string s; pragma(msg, __traits(getAttributes, s)); =20 prints: =20 tuple('c') =20 If there are no user defined attributes for the symbol, an empty tuple is=returned.The expression tuple can be turned into a manipulatable tuple: =20 template Tuple(T...) { alias T Tuple; } =20 enum EEE =3D 7; ["hello"] struct SSS { } [3] { [4][EEE][SSS] int foo; } =20 alias Tuple!(__traits(getAttributes, foo)) TP; =20 pragma(msg, TP); pragma(msg, TP[2]); =20 prints: =20 tuple(3,4,7,(SSS)) 7 =20 and of course the tuple types can be used to declare things: =20 TP[3] a; // a is declared as an SSS =20 The attribute of the type name is not the same as the attribute of the va=riable:=20 pragma(msg, __traits(getAttributes, typeof(a)); =20 prints: =20 tuple("hello") =20 Of course, the real value of UDA's is to be able to create user defined t=ypes withspecific values. Having attribute values of basic types does not scale. The attribute tuples can be manipulated like any other tuple, and can be passed as the argument list to a template. =20 Whether the attributes are values or types is up to the user, and whether=laterattributes accumulate or override earlier ones is also up to how the user interprets them.I wonder what are the benefits over a library solution. Something like struct UserDefinedAttribute(Args...) { alias Args[0 .. $ -1] attributes; } unittest { UserDefinedAttribute!("my attr", int) a; UserDefinedAttribute!("my attr", 4, int) b; import std.stdio; writeln(typeof(a).attributes.stringof); writeln(typeof(b).attributes.stringof); } which admittedly has less syntactical appeal (and probably other problems) but can maybe improved. But to which point. What do you gain by adding it to the core language? Jens
Nov 06 2012
On Tuesday, 6 November 2012 at 09:24:58 UTC, Jens Mueller wrote:which admittedly has less syntactical appeal (and probably other problems) but can maybe improved. But to which point. What do you gain by adding it to the core language? JensIn the initial discussions, I was hoping that the symbol itself would be made available in some fashion. For example, enabling something like this: template Test(alias sym) { pragma(msg, "test attribute was attached to:"); pragma(msg, sym); enum Test = true; } [Test] int a; However, I can imagine that it's always possible to work around this by doing the actual work later when both the symbol and attribute are available.
Nov 06 2012
Jens Mueller wrote:Walter Bright wrote:gain_163042.htmlReferences: =20 http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_a=oposal_yeah_another_one_163246.html=20 http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_pr==3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=20 Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor). =20 You can download it here and try it out: =20 http://ftp.digitalmars.com/dmd2beta.zip =20 As a bonus, that beta also can generate Win64 executables, and you can even symbolically debug them with VS! (Thanks to Rainer Sch=C3=BCtze for his invaluable help with that). =20 Here's the rather skimpy and lame spec I banged out: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=attachedUser Defined Attributes ----------------------- =20 User Defined Attributes (UDA) are compile time expressions that can be =manipulatedto a declaration. These attributes can then be queried, extracted, and =nated:at compile time. There is no runtime component to them. =20 Grammatically, a UDA is a StorageClass: =20 StorageClass: UserDefinedAttribute =20 UserDefinedAttribute: [ ArgumentList ] =20 And looks like: =20 [ 3 ] int a; [ "string", 7 ]: int b; =20 If there are multiple UDAs in scope for a declaration, they are concate=is returned.=20 [ 1 ] { [ 2 ] int a; // has UDA's [1,2] [ "string" ] int b; // has UDA's [1,"string"] } =20 UDA's can be extracted into an expression tuple using __traits: =20 [ 'c' ] string s; pragma(msg, __traits(getAttributes, s)); =20 prints: =20 tuple('c') =20 If there are no user defined attributes for the symbol, an empty tuple =variable:The expression tuple can be turned into a manipulatable tuple: =20 template Tuple(T...) { alias T Tuple; } =20 enum EEE =3D 7; ["hello"] struct SSS { } [3] { [4][EEE][SSS] int foo; } =20 alias Tuple!(__traits(getAttributes, foo)) TP; =20 pragma(msg, TP); pragma(msg, TP[2]); =20 prints: =20 tuple(3,4,7,(SSS)) 7 =20 and of course the tuple types can be used to declare things: =20 TP[3] a; // a is declared as an SSS =20 The attribute of the type name is not the same as the attribute of the =types with=20 pragma(msg, __traits(getAttributes, typeof(a)); =20 prints: =20 tuple("hello") =20 Of course, the real value of UDA's is to be able to create user defined=er laterspecific values. Having attribute values of basic types does not scale. The attribute tuples can be manipulated like any other tuple, and can be passed as the argument list to a template. =20 Whether the attributes are values or types is up to the user, and wheth=No need to reply. Since you said already "Yes, you can attach them to other symbols, including user defined types." That wasn't obvious from the examples. That's why it looked initially limited to me. Jensattributes accumulate or override earlier ones is also up to how the user interprets them.=20 I wonder what are the benefits over a library solution. Something like =20 struct UserDefinedAttribute(Args...) { alias Args[0 .. $ -1] attributes; } =20 unittest { UserDefinedAttribute!("my attr", int) a; UserDefinedAttribute!("my attr", 4, int) b; =20 import std.stdio; writeln(typeof(a).attributes.stringof); writeln(typeof(b).attributes.stringof); } =20 which admittedly has less syntactical appeal (and probably other problems) but can maybe improved. But to which point. What do you gain by adding it to the core language?
Nov 06 2012
Tooo much fun! Argh, _must_ _stop_ _playing_ and actually work ;( ["int a;"] class A { } class B : A { mixin(__traits(getAttributes, typeof(super))[0]); } can't wait to see all the creative uses this will enable!
Nov 06 2012
On Tuesday, 6 November 2012 at 10:10:37 UTC, Tove wrote:Tooo much fun! Argh, _must_ _stop_ _playing_ and actually work ;( ["int a;"] class A { } class B : A { mixin(__traits(getAttributes, typeof(super))[0]); } can't wait to see all the creative uses this will enable!Or obfuscation :)
Nov 06 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:===================================================== User Defined Attributes -----------------------Attributes on overloads are critical. Currently fails: module test; [1] void foo(); [2] void foo(int x); template Tuple(A...) { alias A Tuple; } void main() { foreach (o; __traits(getOverloads, test, "foo")) { alias Tuple!(__traits(getAttributes, o)) attrs; pragma(msg, attrs.stringof); } } Compiler outputs: () ()
Nov 06 2012
On 11/6/2012 4:18 AM, Max Samukha wrote:Attributes on overloads are critical. Currently fails:That should work. Will investigate.
Nov 06 2012
On 11/6/2012 4:18 AM, Max Samukha wrote:Attributes on overloads are critical. Currently fails:Found & fixed. Thanks!
Nov 06 2012
How do the attributes interact with inheritance ? What happens when one inherits an attribute-decorated class ? I can picture both situations, when you would like to see the attributes inherited, and when you would prefer them dropped.
Nov 06 2012
On 11/6/2012 4:24 AM, angel wrote:How do the attributes interact with inheritance ? What happens when one inherits an attribute-decorated class ?The attributes are for the symbol, not the type.
Nov 06 2012
On 2012-11-06 08:55, Walter Bright wrote:References: http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor).This is so cool. Although I would have expected it to have a slightly different syntax. Also have a more key-value like mapping, something like this: mtype("key" : "value") int a; or mtype(key : "value") int a; mtype(key : "val1", key2 : "val2") int foo; mtype("value") int b; mtype int c; Not it's just a bunch of values attached to a symbol, as I see it. -- /Jacob Carlborg
Nov 06 2012
On Tuesday, 6 November 2012 at 13:08:15 UTC, Jacob Carlborg wrote:Also have a more key-value like mapping, something like this:We can always use custom types to get this kind of thing. struct key { string value; } [key("value")] foo
Nov 06 2012
On 2012-11-06 14:17, Adam D. Ruppe wrote:We can always use custom types to get this kind of thing. struct key { string value; } [key("value")] fooRight, good point. But I would still like to somehow be able to name an attribute. If one just need to mark a symbol, i.e. test void foo () {} Then one either have to use a string literal or something like a dummy variable/type. ["test"] void foo () {} enum test = "test"; [test] void foo () {} Or struct test {} [test()] void foo () {} -- /Jacob Carlborg
Nov 06 2012
On 11/6/2012 5:57 AM, Jacob Carlborg wrote:But I would still like to somehow be able to name an attribute. If one just need to mark a symbol, i.e. test void foo () {} Then one either have to use a string literal or something like a dummy variable/type. ["test"] void foo () {}Which does exactly what you ask for.enum test = "test"; [test] void foo () {}or: enum EEE; [EEE] void foo() { }
Nov 06 2012
On 2012-11-06 16:15, Walter Bright wrote:First, I didn't know you could have an empty enum. Second, that was my point. I don't like the need for a dummy/empty enum, or the use of a string literal. -- /Jacob Carlborgenum test = "test"; [test] void foo () {}or: enum EEE; [EEE] void foo() { }
Nov 06 2012
On 11/6/2012 7:31 AM, Jacob Carlborg wrote:On 2012-11-06 16:15, Walter Bright wrote:I see your point, but if such was implemented that way, then the UDAs would be extremely limited, and there'd be all sorts of issues with name scoping. Pretty much all that would have to not only be reinvented, but reams of documentation would have to be crafted explaining how it is different from normal names.First, I didn't know you could have an empty enum. Second, that was my point. I don't like the need for a dummy/empty enum, or the use of a string literal.enum test = "test"; [test] void foo () {}or: enum EEE; [EEE] void foo() { }
Nov 06 2012
On 2012-11-06 16:42, Walter Bright wrote:I see your point, but if such was implemented that way, then the UDAs would be extremely limited, and there'd be all sorts of issues with name scoping. Pretty much all that would have to not only be reinvented, but reams of documentation would have to be crafted explaining how it is different from normal names.No, I don't think so, see one of my other replies: http://forum.dlang.org/thread/k7afq6$2832$1 digitalmars.com?page=6#post-k7bbsu:2411ls:241:40digitalmars.com -- /Jacob Carlborg
Nov 06 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration.Hmmm, it didn't work on the most important place for my use case, function parameters: void a(["test"] int foo) { pragma(msg, __traits(getAttributes, foo)); } test.d(1): Error: basic type expected, not [ test.d(1): Error: found 'int' when expecting ')' test.d(1): Error: semicolon expected following function declaration test.d(1): Error: no identifier for declarator foo test.d(1): Error: semicolon expected, not ')' test.d(1): Error: Declaration expected, not ')' The reason why this is important to me is I have a nice automatic form builder given a function signature. I'd like to add things like hints about the params that my existing code can take a look at. (a problem that might remain is being able to reference the parameters outside... I use a ParameterTypeTuple and .stringof right now but that probably won't work for getAttributes. But we can always solve that later.)
Nov 06 2012
You can put the attribute on the function. There are a couple of go libraries that use struct tags in a similar way. Such as code.google.com/p/gorest On 6 Nov 2012 15:15, "Adam D. Ruppe" <destructionator gmail.com> wrote:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration.Hmmm, it didn't work on the most important place for my use case, function parameters: void a(["test"] int foo) { pragma(msg, __traits(getAttributes, foo)); } test.d(1): Error: basic type expected, not [ test.d(1): Error: found 'int' when expecting ')' test.d(1): Error: semicolon expected following function declaration test.d(1): Error: no identifier for declarator foo test.d(1): Error: semicolon expected, not ')' test.d(1): Error: Declaration expected, not ')' The reason why this is important to me is I have a nice automatic form builder given a function signature. I'd like to add things like hints about the params that my existing code can take a look at. (a problem that might remain is being able to reference the parameters outside... I use a ParameterTypeTuple and .stringof right now but that probably won't work for getAttributes. But we can always solve that later.)
Nov 06 2012
On Tuesday, 6 November 2012 at 13:55:49 UTC, Rory McGuire wrote:You can put the attribute on the function.Yeah, but that's an awfully roundabout way to add an attribute to the parameter... if it went on func params: void foo([Hint("this does something")] string something) {} otherwise we'd have to do something like [ParamHint("something", "this does something")] void foo(string something) {} Which isn't really ahead from the old hack of enum attr_foo_someting = Hint(""); and has similar problems in matching names. It's a little better but not as good as it could be.
Nov 06 2012
On Tuesday, 6 November 2012 at 14:05:46 UTC, Adam D. Ruppe wrote:On Tuesday, 6 November 2012 at 13:55:49 UTC, Rory McGuire wrote:What if the data in the attribute needs to be specific to the symbol on which the attribute is set on? Can you query the symbol from inside the attribute? What if the attribute needs to change the symbol being defined? For instance (using commonly desired syntax): flags enum A { ... } the "flags" attribute would replace the declaraction of A with another enum declaration with the same name and same members, but with replaced initialization and would static assert(false, "flags enum can't have initializers") if any initializers are given. The existing "[data] declaration" is one thing. It adds compile-time data to symbols, which is very very important, but it's not the only thing that is needed. What I described above is not quite an attribute, but an annotation. The semantics of attributes as Walter made them is perfect. The annotation should be defined like so: template myAnnotation(alias symbol, annot_args...) { // ... ["myAnnoration adds this attribute"] alias symbol myAnnotation; // or alias anything else if a change in necessary. } myAnnotation(arg1, arg2, arg3) class Declaration { } here the "symbol" is passed to the template as the first parameter and the parameters in the parentheses are passes after it. It's basically a thin syntactic sugar over some manual (and very ugly) manual template instantiations (and mixins), so it doesn't add anything new. Annotations then become a way to statically replace declarations. This would be perfect to replace Scoped!MyClass mc; with: scoped MyClass mc; Which looks quite like a very beautiful built-in syntax, but is actually a library solution. IMHO, Attributes as they are should stay, but annotations should be added. P.S. Thank you, Walter very very much for making attributes!!! :-)You can put the attribute on the function.Yeah, but that's an awfully roundabout way to add an attribute to the parameter... if it went on func params: void foo([Hint("this does something")] string something) {} otherwise we'd have to do something like [ParamHint("something", "this does something")] void foo(string something) {} Which isn't really ahead from the old hack of enum attr_foo_someting = Hint(""); and has similar problems in matching names. It's a little better but not as good as it could be.
Nov 06 2012
On 2012-11-06 15:23, Gor Gyolchanyan wrote:What if the data in the attribute needs to be specific to the symbol on which the attribute is set on? Can you query the symbol from inside the attribute? What if the attribute needs to change the symbol being defined? For instance (using commonly desired syntax): flags enum A { ... } the "flags" attribute would replace the declaraction of A with another enum declaration with the same name and same members, but with replaced initialization and would static assert(false, "flags enum can't have initializers") if any initializers are given. The existing "[data] declaration" is one thing. It adds compile-time data to symbols, which is very very important, but it's not the only thing that is needed. What I described above is not quite an attribute, but an annotation. The semantics of attributes as Walter made them is perfect. The annotation should be defined like so: template myAnnotation(alias symbol, annot_args...) { // ... ["myAnnoration adds this attribute"] alias symbol myAnnotation; // or alias anything else if a change in necessary. } myAnnotation(arg1, arg2, arg3) class Declaration { } here the "symbol" is passed to the template as the first parameter and the parameters in the parentheses are passes after it. It's basically a thin syntactic sugar over some manual (and very ugly) manual template instantiations (and mixins), so it doesn't add anything new. Annotations then become a way to statically replace declarations. This would be perfect to replace Scoped!MyClass mc; with: scoped MyClass mc; Which looks quite like a very beautiful built-in syntax, but is actually a library solution. IMHO, Attributes as they are should stay, but annotations should be added. P.S. Thank you, Walter very very much for making attributes!!! :-)I like this proposal as well. -- /Jacob Carlborg
Nov 06 2012
For the syntax maybe it's better something like () instead of [], so it becomes more greppable and more easy to tell apart visually from the array literals: (1, "xx", Foo) int x; Supporting annotations for function arguments is probably an important sub-feature. Yesterday I was discussing about the bug-prone nature of foreach loops on a struct array, and one of the solutions I've suggested was a user-defined annotation for the programmer to denote that she wants to modify just the copy: struct Foo {} Foo[10] foos; foreach ( copy f; foos) { ... } With UDA syntax: foreach ([Copy] f; foos) { ... } Or: foreach ( (Copy) f; foos) { ... } But I think there's no way to tell the compiler to give a compile-time error if such annotation is not present there (unless there's "ref"). --------------------- Gor Gyolchanyan:flags enum A { ... } the "flags" attribute would replace the declaraction of A with another enum declaration with the same name and same members, but with replaced initialization and would static assert(false, "flags enum can't have initializers") if any initializers are given.I appreciate your idea (I think of user-defined attributes also as ways to extend the type system), But I know the engineer in Walter prefers extra-simple ideas, so maybe your idea will not be accepted :-) But let's see. Bye, bearophile
Nov 06 2012
On 11/6/2012 8:23 AM, bearophile wrote:Supporting annotations for function arguments is probably an important sub-feature.It would be a significant extension, and so I'd like to see a compelling use case first.Yesterday I was discussing about the bug-prone nature of foreach loops on a struct array, and one of the solutions I've suggested was a user-defined annotation for the programmer to denote that she wants to modify just the copy: struct Foo {} Foo[10] foos; foreach ( copy f; foos) { ... } With UDA syntax: foreach ([Copy] f; foos) { ... } Or: foreach ( (Copy) f; foos) { ... } But I think there's no way to tell the compiler to give a compile-time error if such annotation is not present there (unless there's "ref").User defined attributes cannot invent new semantics for the language. And besides, 'ref' already does what you suggest.
Nov 06 2012
Walter Bright:It would be a significant extension, and so I'd like to see a compelling use case first.Right. Combined with the trait to read function arguments, it's useful to add semantics to function arguments. This is good.User defined attributes cannot invent new semantics for the language.Right, that's my point :-)And besides, 'ref' already does what you suggest.Nope. I have discussed the topic here: http://forum.dlang.org/thread/znbtczbgipqqzllafmzk forum.dlang.org "ref" is useful to denote Case2 of that post of mine. But the copy annotation I was talking here is the very uncommon (but unfortunately often used by mistake, and common source of bugs) Case3. Bye, bearophile
Nov 06 2012
On 11/6/2012 8:47 AM, bearophile wrote:Walter Bright:Ok, I ask again, what use case for a UDA is there for function parameters? (Note that IDL isn't it, as D already has enough parameter attributes to support IDL.)It would be a significant extension, and so I'd like to see a compelling use case first.Right. Combined with the trait to read function arguments, it's useful to add semantics to function arguments. This is good.So it cannot work for the use case you suggested. I'm still asking for a compelling use case.User defined attributes cannot invent new semantics for the language.Right, that's my point :-)I don't see how having the user add a UDA is better than having the user add "const".And besides, 'ref' already does what you suggest.Nope. I have discussed the topic here: http://forum.dlang.org/thread/znbtczbgipqqzllafmzk forum.dlang.org "ref" is useful to denote Case2 of that post of mine. But the copy annotation I was talking here is the very uncommon (but unfortunately often used by mistake, and common source of bugs) Case3.
Nov 06 2012
On Tuesday, 6 November 2012 at 17:00:27 UTC, Walter Bright wrote:Ok, I ask again, what use case for a UDA is there for function parameters? (Note that IDL isn't it, as D already has enough parameter attributes to support IDL.)What »IDL« are you referring to here? At least as far as I am aware, IDL usually just refers to an »interface definition language« in general, so I'm not quite sure what you mean if you are talking about »enough to support IDL«. Actually, the Thrift IDL would be a perfect example of how attributes on parameters can be useful. A simple service definition in a .thrift could look like this: --- service Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op) } --- Note that the parameters are given explicit ids, similar to regular struct fields in Thrift, to provide robustness of the generated code against future RPC protocol changes (e.g. addition of parameters). Currently, the equivalent D code for the interface would look something like this: --- interface Calculator : SharedService { int calculate(int a, int b, Op op); enum methodMeta = [ TMethodMeta(`calculate`, [TParamMeta(`a`, 1), TParamMeta(`b`, 2), TParamMeta(`op`, 3)] ) ]; } --- Being able to assign the IDs in-line using UDAs would make for a much more natural method declaration syntax. David
Nov 06 2012
Am 06.11.2012 18:32, schrieb David Nadlinger:On Tuesday, 6 November 2012 at 17:00:27 UTC, Walter Bright wrote:perfect example - thx alotOk, I ask again, what use case for a UDA is there for function parameters? (Note that IDL isn't it, as D already has enough parameter attributes to support IDL.)What »IDL« are you referring to here? At least as far as I am aware, IDL usually just refers to an »interface definition language« in general, so I'm not quite sure what you mean if you are talking about »enough to support IDL«. Actually, the Thrift IDL would be a perfect example of how attributes on parameters can be useful. A simple service definition in a .thrift could look like this: --- service Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op) }
Nov 06 2012
Am 06.11.2012 18:32, schrieb David Nadlinger:On Tuesday, 6 November 2012 at 17:00:27 UTC, Walter Bright wrote:http://svn.apache.org/repos/asf/thrift/trunk/tutorial/tutorial.thriftOk, I ask again, what use case for a UDA is there for function parameters? (Note that IDL isn't it, as D already has enough parameter attributes to support IDL.)What »IDL« are you referring to here? At least as far as I am aware, IDL usually just refers to an »interface definition language« in general, so I'm not quite sure what you mean if you are talking about »enough to support IDL«. Actually, the Thrift IDL would be a perfect example of how attributes on parameters can be useful. A simple service definition in a .thrift could look like this:
Nov 06 2012
On Tuesday, 6 November 2012 at 17:32:55 UTC, David Nadlinger wrote:Currently, the equivalent D code for the interface would look something like this: --- interface Calculator : SharedService { int calculate(int a, int b, Op op); enum methodMeta = [ TMethodMeta(`calculate`, [TParamMeta(`a`, 1), TParamMeta(`b`, 2), TParamMeta(`op`, 3)] ) ]; } ---(Note that this is actual code that has the intended result with DMD 2.060. Now with UDAs in the picture, one could obviously make TMethodMeta a method-level annotation.) David
Nov 06 2012
On 11/6/2012 9:32 AM, David Nadlinger wrote:On Tuesday, 6 November 2012 at 17:00:27 UTC, Walter Bright wrote:Back in the olden days, Microsoft released a language called IDL (Interface Definition Language) where you retyped your C function declarations and annotated them with in, out, and inout. This was used to connect with COM. I think Microsoft replaced it with extensions to the C compiler.Ok, I ask again, what use case for a UDA is there for function parameters? (Note that IDL isn't it, as D already has enough parameter attributes to support IDL.)What »IDL« are you referring to here? At least as far as I am aware, IDL usually just refers to an »interface definition language« in general, so I'm not quite sure what you mean if you are talking about »enough to support IDL«.Actually, the Thrift IDL would be a perfect example of how attributes on parameters can be useful. A simple service definition in a .thrift could look like this: --- service Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op)What does this mean? That 'a' is the first parameter and has type i32?} --- Note that the parameters are given explicit ids, similar to regular struct fields in Thrift, to provide robustness of the generated code against future RPC protocol changes (e.g. addition of parameters). Currently, the equivalent D code for the interface would look something like this: --- interface Calculator : SharedService { int calculate(int a, int b, Op op); enum methodMeta = [ TMethodMeta(`calculate`, [TParamMeta(`a`, 1), TParamMeta(`b`, 2), TParamMeta(`op`, 3)] ) ]; } --- Being able to assign the IDs in-line using UDAs would make for a much more natural method declaration syntax.
Nov 06 2012
On Tuesday, 6 November 2012 at 17:51:28 UTC, Walter Bright wrote:On 11/6/2012 9:32 AM, David Nadlinger wrote:It means that ›a‹ has type i32 and is the parameter with ID 1. The parameter list could have also been (42:i32 a, 5:i32 b, 1:Op op). If no ids are specified, negative ones are auto-assigned by the compiler, starting from -1. Davidservice Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op)What does this mean? That 'a' is the first parameter and has type i32?
Nov 06 2012
On 11/6/2012 10:01 AM, David Nadlinger wrote:> On Tuesday, 6 November 2012 at 17:51:28 UTC, Walter Bright wrote:Ok, but a type is not a UDA <g>.On 11/6/2012 9:32 AM, David Nadlinger wrote:It means that ›a‹ has type i32service Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op)What does this mean? That 'a' is the first parameter and has type i32?and is the parameter with ID 1. The parameter list could have also been (42:i32 a, 5:i32 b, 1:Op op). If no ids are specified, negative ones are auto-assigned by the compiler, starting from -1.Why isn't 'a' the ID?
Nov 06 2012
On Tuesday, 6 November 2012 at 18:06:15 UTC, Walter Bright wrote:On 11/6/2012 10:01 AM, David Nadlinger wrote:> On Tuesday, 6 November 2012 at 17:51:28 UTC, Walter Bright wrote:That was never my point. I could have also just said »Parameters to Thrift RPC methods have numerical IDs«, but I though a code example might be clearer. Apparently, I was wrong. ;)type i32?On 11/6/2012 9:32 AM, David Nadlinger wrote:service Calculator { i32 calculate(1:i32 a, 2:i32 b, 3:Op op)What does this mean? That 'a' is the first parameter and hasIt means that ›a‹ has type i32Ok, but a type is not a UDA <g>.Why isn't 'a' the ID?a is just a name used for documentation purposes – they show up in target language code generated by the Thrift compiler from the IDL file, for implementations which rely on code generation [1]. On the wire, all struct fields and method parameters are tagged with integer IDs, and those are actually what's used for (de-)serializations. This use of IDs is a common feature of »high-performance« RPC protocols designed to support interface evolution, e.g. Google's protobuf makes use of them as well. David [1] The compiler module for D only translates type and service definitions to D structs/interfaces, the rest happens using CTFE magic, which enables use of Thrift without writing .thrift files (in fact, they can be generated _from_ D code using CTFE). In theory, the compiler could be completely replaced using ImportStatements and CTFE, but I never got that out of the prototype stage due to compiler bugs.
Nov 06 2012
Walter Bright:I don't see how having the user add a UDA is better than having the user add "const".I am still referring to this: http://forum.dlang.org/thread/znbtczbgipqqzllafmzk forum.dlang.org "const" is not enough. Const is optional and it's useful for Case1, this means when you don't want to modify the struct (even if maybe sometimes you can't use a const, because not always is usable as const, like some ranges, but this is beside the point). Often you want Case2 but you forget the "ref" so instead of Case2 you fall in Case3 by mistake. So to avoid that common bug that proposal was to statically refuse code like this because it's ambiguous: is the programmer trying to use Case2 or Case3 here? void main() { auto data = [0, 1, 2, 3]; foreach (x; data) x++; } So you use: // Case1 void main() { auto data = [0, 1, 2, 3]; foreach (x; data) writeln(x); foreach (const x; data) writeln(x); } // Case2 void main() { auto data = [0, 1, 2, 3]; foreach (ref x; data) x++; } // Case3 (uncommon) void main() { auto data = [0, 1, 2, 3]; foreach ( copy x; data) writeln(++x); } Bye, bearophile
Nov 06 2012
On 11/6/2012 9:52 AM, bearophile wrote:// Case3 (uncommon) void main() { auto data = [0, 1, 2, 3]; foreach ( copy x; data) writeln(++x); }x is a value type, and it is already copied. And if you did want to copy it, foreach (x; data) { auto copy = x; writeln(++copy); } I don't see what the annotation buys you, even if it could be made to work.
Nov 06 2012
Walter Bright: First of all, assume I know how to use and abuse foreach in all the common and uncommon cases. So in this discussion we can assume we both know well enough what we are talking about. What I am discussing about is a real problem in real D code, a bug-prone characteristic of foreach. We may accept the situation like it is, and do nothing, or we may want to improve the situation. But this doesn't change the fact that there is a problem in the D design of foreach loops when you scan an array of structs. This problem is recognized by several other persons in the D community, it's not a creation of my mind. That said, let me try again to explain the problem.The point of Case3 is not that I want to copy it again. The annotation by itself buys you nothing. But he annotation is not meant to be the only change in D. There are two changes that need to happen at the same time: Change1) Make this a compile-time error, this means if you write this code, the compiler refuses your code statically. So "x" despite not being const is like being const, because the compiler does not let you modify it inside the loop, if you try, it gives you an error (so maybe it's simpler to implement this Change1 really as putting "const" on default on x even if you don't write auto data = [1, 2, 3]; foreach (x; data) x++; // compilation error here Change2) Introduce an annotation like mutable to denote Case3 (I have replaced copy with mutable to make this explanation more clear for you, so maybe mutable is really a better name for this idea). This means this is accepted, it's like saying that x is not const: foreach ( mutable x; data) writeln(++x); // OK Why I have suggested this pair of changes? The only purpose of those two changes is to remove one bug-prone situation from D code. The situation is this: struct Foo { int x; } auto data = [Foo(1), Foo(2), Foo(3)]; foreach (f; data) f.x++; What is the programmer trying to write there? Was she trying to change the structs inside data (Case2)? Or was she trying to modify just their copy (Case3)? The problem is that usually programmers want Case1 or Case2, they most times do not want to write a Case3. But it's very easy to forget "ref". So the programmer wants to write a Case2 but often writes a Case3 by mistake. The combined presence of Change1 and Change2 removes this source of errors. Because now if you forget "ref" the compiler refuses your code statically. If you want Case3 you add a copy. In most cases you really meant to use a Case2 so you add "ref" and the D compiler has caught your bug! If you were trying to write a Case1 you didn't put inside the loop code that modifies the struct, so the error of Change1 is not triggered and you need no copy nor ref. I have written probably 250_000+ lines of good-quality D1/D2 code, and bugs like this are still present in my code, so I'd like to remove them from D once and for all: struct Foo { int x; } auto data = [Foo(1), Foo(2), Foo(3)]; foreach (f; data) f.x++; Bye, bearophile// Case3 (uncommon) void main() { auto data = [0, 1, 2, 3]; foreach ( copy x; data) writeln(++x); }x is a value type, and it is already copied. And if you did want to copy it, foreach (x; data) { auto copy = x; writeln(++copy); } I don't see what the annotation buys you, even if it could be made to work.
Nov 06 2012
On Tuesday, 6 November 2012 at 16:41:22 UTC, Walter Bright wrote:It would be a significant extension, and so I'd like to see a compelling use case first.What do you consider to be compelling use cases for UDAs on functions? Going back to the links on the original post, we have: "I have numerous systems that need to scan the module for things marked accordingly to automate bindings to their respective systems." Putting them on parameters also helps with this. Script languages have to deal with parameters. Editors might. And, of course, I've already talked about automatic UI generation. Here's another one: named parameters. Of course, there's D names, but suppose you have to hook into another naming scheme that uses characters that aren't valid D names? An external system might send you "log-in?user-id=foo". You are doing a library to automatically call a class: class Handler { [ExternalName("log-in")] /* we can do this now */ void logIn([ExternalName("user-id")] string userId) {} /* but the parameter, which is the same concept, doesn't work */ }
Nov 06 2012
On Tuesday, 6 November 2012 at 17:16:34 UTC, Adam D. Ruppe wrote:[ExternalName("log-in")] /* we can do this now */ void logIn([ExternalName("user-id")] string userId)BTW we could conceivably do: [ExternalName("log-in"), ParameterAttribute!("userId")(ExternalName("user-id")] void logIn(string userId) {} Where the ParameterAttribute simply matches up the param by name or by position (if you pass an int instead of string) and puts the other argument in that map. When you scan the function for attributes, you keep your eye open for that ParameterAttribute thingy and match it up in the library. So if it is too painful to put it in the compiler, we could make it work in the library.
Nov 06 2012
On 11/6/2012 9:26 AM, Adam D. Ruppe wrote:On Tuesday, 6 November 2012 at 17:16:34 UTC, Adam D. Ruppe wrote:That looks like it can work. It's an interesting idea. Other possibilities are: 1. Use a naming convention for the parameters, and then have an attribute for the function that more or less means that the function follows that naming convention. Naming conventions are often used in systems that don't have UDAs. 2. Use a user-defined wrapper type for the parameter. Then query for that type.[ExternalName("log-in")] /* we can do this now */ void logIn([ExternalName("user-id")] string userId)BTW we could conceivably do: [ExternalName("log-in"), ParameterAttribute!("userId")(ExternalName("user-id")] void logIn(string userId) {} Where the ParameterAttribute simply matches up the param by name or by position (if you pass an int instead of string) and puts the other argument in that map. When you scan the function for attributes, you keep your eye open for that ParameterAttribute thingy and match it up in the library. So if it is too painful to put it in the compiler, we could make it work in the library.
Nov 06 2012
Am 06.11.2012 17:41, schrieb Walter Bright:On 11/6/2012 8:23 AM, bearophile wrote:Having seen how annotations for function arguments in Java 8 might look like, and the annotations everywhere that we have in the enterprise frameworks, I am weary of such support. -- PauloSupporting annotations for function arguments is probably an important sub-feature.It would be a significant extension, and so I'd like to see a compelling use case first.
Nov 06 2012
On 11/06/2012 05:41 PM, Walter Bright wrote:On 11/6/2012 8:23 AM, bearophile wrote:The use cases are the same as for other declarations. Parameter declarations are not special.Supporting annotations for function arguments is probably an important sub-feature.It would be a significant extension, and so I'd like to see a compelling use case first. ...
Nov 06 2012
Am 06.11.2012 14:14, schrieb Adam D. Ruppe:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:sad - but its still very young feature :) im using something like an description on my methods to describe parameter "features" for an resource manager - something like "read", "write", "copy", "read_write" etc. to have this at compiletime available by using UDAs on parameters + an compiletime generator would be absolutely briliant my vote +1 for UDAs on parametersUser Defined Attributes (UDA) are compile time expressions that can be attached to a declaration.Hmmm, it didn't work on the most important place for my use case, function parameters: void a(["test"] int foo) { pragma(msg, __traits(getAttributes, foo)); }
Nov 06 2012
On 11/6/2012 6:30 AM, dennis luehring wrote:Am 06.11.2012 14:14, schrieb Adam D. Ruppe:But there's already out=write, read=all of them, read_write=ref, copy=not a ref or an out. I don't know what use UDAs would be for parameters.On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:sad - but its still very young feature :) im using something like an description on my methods to describe parameter "features" for an resource manager - something like "read", "write", "copy", "read_write" etc.User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration.Hmmm, it didn't work on the most important place for my use case, function parameters: void a(["test"] int foo) { pragma(msg, __traits(getAttributes, foo)); }
Nov 06 2012
On Tuesday, 6 November 2012 at 15:18:55 UTC, Walter Bright wrote:I don't know what use UDAs would be for parameters.It's pretty much the same as anywhere else: to add useful data for reflection. A few I'd use it for is providing user visible data like label and hint for automatic UI generation, or styling hints again for the auto ui (e.g. "use a multi-line input for this string"). We could also potentially put validation in there, though this may be on the type as well. Or put on info to check for availability of a username. If you do an automatic UI generator, attributes on the parameters have a lot of uses. Other than that, well, I don't know, but that's probably just because I haven't done it yet!
Nov 06 2012
Am 06.11.2012 16:18, schrieb Walter Bright:> On 11/6/2012 6:30 AM, dennis luehring wrote:> Am 06.11.2012 14:14, schrieb Adam D. Ruppe: >> On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote: >>> User Defined Attributes (UDA) are compile time expressions that >>> can be attached to a declaration. >> >> Hmmm, it didn't work on the most important place for my use case, >> function parameters: >> >> void a(["test"] int foo) { >> pragma(msg, __traits(getAttributes, foo)); >> } > > sad - but its still very young feature :) > > im using something like an description on my methods to describeparameter> "features" for an resource manager - something like "read","write", "copy",> "read_write" etc. But there's already out=write, read=all of them, read_write=ref,copy=not a refor an out.and now expand that to an higher level manager that use such information for implementing(generating) runtime loading and locking strategies in a tree/graph based environment - based on the parameters needs ... i've got something like that in C++ using its own interface description language and an generatorI don't know what use UDAs would be for parameters.exact the same as for every other symbol - it enriches the semantic meaning of that symbol :)
Nov 06 2012
On 11/6/2012 8:42 AM, dennis luehring wrote:Am 06.11.2012 16:18, schrieb Walter Bright:> On 11/6/2012 6:30 AM, dennis luehring wrote: > > Am 06.11.2012 14:14, schrieb Adam D. Ruppe: > >> On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote: > >>> User Defined Attributes (UDA) are compile time expressions that > >>> can be attached to a declaration. > >> > >> Hmmm, it didn't work on the most important place for my use case, > >> function parameters: > >> > >> void a(["test"] int foo) { > >> pragma(msg, __traits(getAttributes, foo)); > >> } > > > > sad - but its still very young feature :) > > > > im using something like an description on my methods to describe parameter > > "features" for an resource manager - something like "read", "write", "copy", > > "read_write" etc. > But there's already out=write, read=all of them, read_write=ref, copy=not a ref > or an out. and now expand that to an higher level manager that use such information for implementing(generating) runtime loading and locking strategies in a tree/graph based environment - based on the parameters needs ... i've got something like that in C++ using its own interface description language and an generatorBut D already has parameter attributes that cover those bases. What would UDAs add to that? (I know C++ is deficient in this, which is why IDL was invented, but I don't see what UDAs add to what D already provides - no IDL is needed for D).
Nov 06 2012
Am 06.11.2012 17:50, schrieb Walter Bright:On 11/6/2012 8:42 AM, dennis luehring wrote:just 2 questions: 1. what if my needs are beyond D? for example my idl allows me to define a type based query source for parameters CalculateStuff( TypeX [source="\\placement\(typeA|typeB|typeC)"] my_usage ) this defines the source of assignable objects to this method 2. what is the reason for stopping right before parameters? (except less coding on your side)Am 06.11.2012 16:18, schrieb Walter Bright:> On 11/6/2012 6:30 AM, dennis luehring wrote: > > Am 06.11.2012 14:14, schrieb Adam D. Ruppe: > >> On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote: > >>> User Defined Attributes (UDA) are compile time expressions that > >>> can be attached to a declaration. > >> > >> Hmmm, it didn't work on the most important place for my use case, > >> function parameters: > >> > >> void a(["test"] int foo) { > >> pragma(msg, __traits(getAttributes, foo)); > >> } > > > > sad - but its still very young feature :) > > > > im using something like an description on my methods to describe parameter > > "features" for an resource manager - something like "read", "write", "copy", > > "read_write" etc. > But there's already out=write, read=all of them, read_write=ref, copy=not a ref > or an out. and now expand that to an higher level manager that use such information for implementing(generating) runtime loading and locking strategies in a tree/graph based environment - based on the parameters needs ... i've got something like that in C++ using its own interface description language and an generatorBut D already has parameter attributes that cover those bases. What would UDAs add to that? (I know C++ is deficient in this, which is why IDL was invented, but I don't see what UDAs add to what D already provides - no IDL is needed for D).
Nov 06 2012
On 11/6/2012 9:00 AM, dennis luehring wrote:1. what if my needs are beyond D? for example my idl allows me to define a type based query source for parameters CalculateStuff( TypeX [source="\\placement\(typeA|typeB|typeC)"] my_usage ) this defines the source of assignable objects to this methodHas this capability ever been used?2. what is the reason for stopping right before parameters? (except less coding on your side)It adds significant complexity. I don't think it's a good idea to add significant complexity to the language without a compelling use case. It needs to be something more than just being nice.
Nov 06 2012
Am 06.11.2012 18:14, schrieb Walter Bright:> On 11/6/2012 9:00 AM, dennis luehring wrote:parameters1. what if my needs are beyond D? for example my idl allows me to define a type based query source formy_usage )CalculateStuff( TypeX [source="\\placement\(typeA|typeB|typeC)"]all the while - the complete object-to-object lifecycle of composits etc. is managed by this - no coded object creation is happening its partially based on the naked object pattern the next step will be a complete managed(and hopefully more efficient) loading/locking strategy - but still in around 800k lines of C++ :(this defines the source of assignable objects to this methodHas this capability ever been used?
Nov 06 2012
Le 06/11/2012 18:14, Walter Bright a écrit :On 11/6/2012 9:00 AM, dennis luehring wrote:It remove complexity in the sens it remove special cases. It indeed add complexity for the compiler.1. what if my needs are beyond D? for example my idl allows me to define a type based query source for parameters CalculateStuff( TypeX [source="\\placement\(typeA|typeB|typeC)"] my_usage ) this defines the source of assignable objects to this methodHas this capability ever been used?2. what is the reason for stopping right before parameters? (except less coding on your side)It adds significant complexity. I don't think it's a good idea to add significant complexity to the language without a compelling use case. It needs to be something more than just being nice.
Nov 06 2012
On 11/06/2012 06:31 PM, deadalnix wrote:Le 06/11/2012 18:14, Walter Bright a écrit :But almost none. It is easy to get right.On 11/6/2012 9:00 AM, dennis luehring wrote:It remove complexity in the sens it remove special cases. It indeed add complexity for the compiler.1. what if my needs are beyond D? for example my idl allows me to define a type based query source for parameters CalculateStuff( TypeX [source="\\placement\(typeA|typeB|typeC)"] my_usage ) this defines the source of assignable objects to this methodHas this capability ever been used?2. what is the reason for stopping right before parameters? (except less coding on your side)It adds significant complexity. I don't think it's a good idea to add significant complexity to the language without a compelling use case. It needs to be something more than just being nice.
Nov 06 2012
On Tuesday, 6 November 2012 at 13:14:50 UTC, Adam D. Ruppe wrote:On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:Hmmm, actually it doesn't work in plain function/block scope either. void a() { ["test"] int foo; pragma(msg, __traits(getAttributes, foo)); } Error: found 'int' when expecting ';' following statementUser Defined Attributes (UDA) are compile time expressions that can be attached to a declaration.Hmmm, it didn't work on the most important place for my use case, function parameters: void a(["test"] int foo) { pragma(msg, __traits(getAttributes, foo)); }
Nov 06 2012
On 11/6/2012 7:14 AM, Tove wrote:Hmmm, actually it doesn't work in plain function/block scope either.Right, I don't see a compelling purpose for that, either.
Nov 06 2012
On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:On 11/6/2012 7:14 AM, Tove wrote:Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;Hmmm, actually it doesn't work in plain function/block scope either.Right, I don't see a compelling purpose for that, either.
Nov 06 2012
On 11/6/2012 8:02 AM, Tove wrote:On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:I have no idea how you could make that work.On 11/6/2012 7:14 AM, Tove wrote:Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;Hmmm, actually it doesn't work in plain function/block scope either.Right, I don't see a compelling purpose for that, either.
Nov 06 2012
Am 06.11.2012 17:26, schrieb Walter Bright:On 11/6/2012 8:02 AM, Tove wrote:I can only see it work if the runtime is aware of magic annotations, which are kept in the binary. -- PauloOn Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:I have no idea how you could make that work.On 11/6/2012 7:14 AM, Tove wrote:Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;Hmmm, actually it doesn't work in plain function/block scope either.Right, I don't see a compelling purpose for that, either.
Nov 06 2012
On 11/6/2012 5:14 AM, Adam D. Ruppe wrote:Hmmm, it didn't work on the most important place for my use case, function parameters:It didn't occur to me to enable that.
Nov 06 2012
Le 06/11/2012 16:15, Walter Bright a écrit :On 11/6/2012 5:14 AM, Adam D. Ruppe wrote:It should work everywhere or not work at all.Hmmm, it didn't work on the most important place for my use case, function parameters:It didn't occur to me to enable that.
Nov 06 2012
On 11/6/2012 9:06 AM, deadalnix wrote:> Le 06/11/2012 16:15, Walter Bright a écrit :You can't have pure attributes on function parameters, either. Parameters don't work like regular declarations, never have, and I don't know of a language where they do. They even have a different grammar.On 11/6/2012 5:14 AM, Adam D. Ruppe wrote:It should work everywhere or not work at all.Hmmm, it didn't work on the most important place for my use case, function parameters:It didn't occur to me to enable that.
Nov 06 2012
Am 06.11.2012 18:17, schrieb Walter Bright:> On 11/6/2012 9:06 AM, deadalnix wrote:> Le 06/11/2012 16:15, Walter Bright a écrit :>> On 11/6/2012 5:14 AM, Adam D. Ruppe wrote: >>> Hmmm, it didn't work on the most important place for my use case, >>> function >>> parameters: >> >> It didn't occur to me to enable that. >> > > It should work everywhere or not work at all. You can't have pure attributes on function parameters, either.Parameters don'twork like regular declarations, never have, and I don't know of alanguage wherethey do. They even have a different grammar.but why should an UDA only extend the semantic of regular declarations? can't you please give us a bad-usage example why it is/should be forbidden to use UDA on parameters (and please - we are not talking about pure, in, out and stuff like that)
Nov 06 2012
On 11/6/2012 9:34 AM, dennis luehring wrote:can't you please give us a bad-usage example why it is/should be forbidden to use UDA on parameters (and please - we are not talking about pure, in, out and stuff like that)I believe this is the wrong question. For a new feature, the question should be "why should it be included", not "why shouldn't it be included." For example, UDAs in general are not actually necessary. They can be faked using a naming convention, and such is very common. The trouble, though, is that if one uses UDAs a lot, then the complexity of the naming convention becomes unbearable. It's become clear to me that UDAs can be used a lot, and so more targeted support for them is justified - i.e. a compelling use case. It's hard to see that on parameters, though.
Nov 06 2012
Le 06/11/2012 19:02, Walter Bright a écrit :On 11/6/2012 9:34 AM, dennis luehring wrote:No. It is needed to annotate symbols, uses cases are numerous. Now, if an exception is added, the exception should be justified.can't you please give us a bad-usage example why it is/should be forbidden to use UDA on parameters (and please - we are not talking about pure, in, out and stuff like that)I believe this is the wrong question. For a new feature, the question should be "why should it be included", not "why shouldn't it be included."
Nov 06 2012
On 11/06/2012 07:02 PM, Walter Bright wrote:On 11/6/2012 9:34 AM, dennis luehring wrote:The same holds for arbitrary restrictions. I thought the general agreement was to include the feature. Language features should be as general and as orthogonal as possible and reasonable.can't you please give us a bad-usage example why it is/should be forbidden to use UDA on parameters (and please - we are not talking about pure, in, out and stuff like that)I believe this is the wrong question. For a new feature, the question should be "why should it be included", not "why shouldn't it be included." ...
Nov 06 2012
On Tuesday, 6 November 2012 at 20:41:27 UTC, Timon Gehr wrote:On 11/06/2012 07:02 PM, Walter Bright wrote:Exactly. Looking forward to complaints about impossibility to annotate module declarations.On 11/6/2012 9:34 AM, dennis luehring wrote:The same holds for arbitrary restrictions. I thought the general agreement was to include the feature. Language features should be as general and as orthogonal as possible and reasonable.can't you please give us a bad-usage example why it is/should be forbidden to use UDA on parameters (and please - we are not talking about pure, in, out and stuff like that)I believe this is the wrong question. For a new feature, the question should be "why should it be included", not "why shouldn't it be included." ...
Nov 06 2012
On Tuesday, 6 November 2012 at 17:17:50 UTC, Walter Bright wrote:On 11/6/2012 9:06 AM, deadalnix wrote:> Le 06/11/2012 16:15, Walter Bright a écrit :return value. Actually, it allows custom meta-data everywhere. See a use case here http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute.aspx. I believe Java does the same.case,On 11/6/2012 5:14 AM, Adam D. Ruppe wrote:Hmmm, it didn't work on the most important place for my useYou can't have pure attributes on function parameters, either. Parameters don't work like regular declarations, never have, and I don't know of a language where they do. They even have a different grammar.It should work everywhere or not work at all.function parameters:It didn't occur to me to enable that.
Nov 06 2012
On 11/6/2012 10:42 AM, Max Samukha wrote:Actually, it allows custom meta-data everywhere. See a use case here http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute.aspx.Thank you. Under the "Remarks" section they give some good examples. As for the return value attributes, I think that can be handled by attributing the function symbol itself, as it can only have one return type.
Nov 06 2012
On Tuesday, 6 November 2012 at 19:12:54 UTC, Walter Bright wrote:As for the return value attributes, I think that can be handled by attributing the function symbol itself, as it can only have one return type.Theoretically there might be cases requiring an attribute of the same class both on the function and on the return value. Then differentiation of function and return value attributes would be necessary. Anybody has an example?
Nov 06 2012
On 11/6/2012 11:42 AM, Max Samukha wrote:> Theoretically there might be cases requiring an attribute of the same class bothon the function and on the return value. Then differentiation of function and return value attributes would be necessary. Anybody has an example?Not a problem, as you'd search the tuple for the attribute that matters anyway.
Nov 06 2012
On Tuesday, 6 November 2012 at 20:14:56 UTC, Walter Bright wrote:On 11/6/2012 11:42 AM, Max Samukha wrote:> Theoretically there might be cases requiring an attribute of the same class bothBy "the same class" I meant: template SomeFunkyID(string id) { } [SomeFunkyID!"boo"] [return: SomeFunkyID!"bar"] void foo(); intended for the return value and which for the function itself. How would I do that if both attributes were piled together in the same tuple?on the function and on the return value. Then differentiationof function andreturn value attributes would be necessary. Anybody has anexample? Not a problem, as you'd search the tuple for the attribute that matters anyway.
Nov 06 2012
On 11/6/2012 12:28 PM, Max Samukha wrote:return value and which for the function itself. How would I do that if both attributes were piled together in the same tuple?Make SomeFunkyID a parameter to a ReturnOnly template that you've defined.
Nov 06 2012
On Tuesday, 6 November 2012 at 20:49:07 UTC, Walter Bright wrote:On 11/6/2012 12:28 PM, Max Samukha wrote:Right. However, the discussion is about adding real attributes to parameters. We all agree that they are not strictly necessary: [ParameterAttributes!(SomeFunkyID!...)] void foo(int x); But that is what people are complaining about because it is inconsistent with other declarations. In other words, if you are going to implement parameter attributes, either go all the way or don't do that at all.intended for the return value and which for the function itself. How would I do that if both attributes were piled together in the same tuple?Make SomeFunkyID a parameter to a ReturnOnly template that you've defined.
Nov 06 2012
On 2012-11-06 19:42, Max Samukha wrote:value. Actually, it allows custom meta-data everywhere. See a use case here http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute.aspx. I believe Java does the same.Yes it does: http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html You need to specify the target tough, like declaration of an annotation: Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface Test { } -- /Jacob Carlborg
Nov 06 2012
On Tuesday, 6 November 2012 at 19:43:54 UTC, Jacob Carlborg wrote:You need to specify the target tough, like declaration of an annotation: Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface Test { }
Nov 06 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:References: http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.htmlI tried to build DMD git for dpaste, so people can play with UDA but DMD segfaults when building Phobos Program received signal SIGSEGV, Segmentation fault. 0x0000000000403179 in ClassDeclaration::getAccess(Dsymbol*) () (gdb) bt Scope*, Dsymbol*) () ScopeDsymbol*) () ScopeDsymbol*) () ScopeDsymbol*) () ScopeDsymbol*, int) () ScopeDsymbol*, int) () ScopeDsymbol*, int) () Well, anyways, I fetched package prepared in first post. So folks, you can play with UDA on http://dpaste.dzfl.pl - by picking DMD2 git - without messing with DMD packages in your OS :) http://dpaste.dzfl.pl/9c2e8b20 Also if I declare string with UDA inside main() I get error: http://dpaste.dzfl.pl/909a34c8
Nov 06 2012
On 11/6/2012 5:23 AM, nazriel wrote:I tried to build DMD git for dpaste, so people can play with UDA but DMD segfaults when building PhobosThe auto tester shows it's working. http://d.puremagic.com/test-results/
Nov 06 2012
Le 06/11/2012 08:55, Walter Bright a écrit :References: http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor). You can download it here and try it out: http://ftp.digitalmars.com/dmd2beta.zip As a bonus, that beta also can generate Win64 executables, and you can even symbolically debug them with VS! (Thanks to Rainer Schütze for his invaluable help with that). Here's the rather skimpy and lame spec I banged out: ===================================================== User Defined Attributes ----------------------- User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration. These attributes can then be queried, extracted, and manipulated at compile time. There is no runtime component to them. Grammatically, a UDA is a StorageClass: StorageClass: UserDefinedAttribute UserDefinedAttribute: [ ArgumentList ] And looks like: [ 3 ] int a; [ "string", 7 ]: int b; If there are multiple UDAs in scope for a declaration, they are concatenated: [ 1 ] { [ 2 ] int a; // has UDA's [1,2] [ "string" ] int b; // has UDA's [1,"string"] } UDA's can be extracted into an expression tuple using __traits: [ 'c' ] string s; pragma(msg, __traits(getAttributes, s)); prints: tuple('c') If there are no user defined attributes for the symbol, an empty tuple is returned. The expression tuple can be turned into a manipulatable tuple: template Tuple(T...) { alias T Tuple; } enum EEE = 7; ["hello"] struct SSS { } [3] { [4][EEE][SSS] int foo; } alias Tuple!(__traits(getAttributes, foo)) TP; pragma(msg, TP); pragma(msg, TP[2]); prints: tuple(3,4,7,(SSS)) 7 and of course the tuple types can be used to declare things: TP[3] a; // a is declared as an SSS The attribute of the type name is not the same as the attribute of the variable: pragma(msg, __traits(getAttributes, typeof(a)); prints: tuple("hello") Of course, the real value of UDA's is to be able to create user defined types with specific values. Having attribute values of basic types does not scale. The attribute tuples can be manipulated like any other tuple, and can be passed as the argument list to a template. Whether the attributes are values or types is up to the user, and whether later attributes accumulate or override earlier ones is also up to how the user interprets them.OK, I may break all the happiness of that news but . . . Tuple in D is notoriously known to be a badly designed feature. Basing more stuff on that just because we have them is short sighted and will only result in D's tuples being broken forever, several tuples implementations for more user confusion, or future major breakage. We still don't have any scheme for a stable D, feature testing or whatever, so everybody should be prepared for many new ICE (or even more fun, bugs). After we all love them or we wouldn't be using D ! Who need a programming language to be stable or reliable ? Surprise feature ! Yaw, no wonder D's toolchain is so wonderfull ! Let's not talk these awesome static code analysis tools, java would become jealous. BTW, I don't really like that syntax, but really, that isn't important.
Nov 06 2012
On 11/6/2012 8:27 AM, deadalnix wrote:OK, I may break all the happiness of that news but . . . Tuple in D is notoriously known to be a badly designed feature. Basing more stuff on that just because we have them is short sighted and will only result in D's tuples being broken forever, several tuples implementations for more user confusion, or future major breakage.The only real trouble with tuples is that functions can't return them.We still don't have any scheme for a stable D, feature testing or whatever,Are you aware of the test suite and the auto-tester?Let's not talk these awesome static code analysis tools, java would become jealous.I have no idea what your point is.
Nov 06 2012
Le 06/11/2012 17:46, Walter Bright a écrit :On 11/6/2012 8:27 AM, deadalnix wrote:If it is the only problem, we have a pandemic spread of hallucinogen trance amongs D users.OK, I may break all the happiness of that news but . . . Tuple in D is notoriously known to be a badly designed feature. Basing more stuff on that just because we have them is short sighted and will only result in D's tuples being broken forever, several tuples implementations for more user confusion, or future major breakage.The only real trouble with tuples is that functions can't return them.Yes, I'm also aware I hit compiler bugs on a daily basis, that my codebase is full of workaround on some of them.We still don't have any scheme for a stable D, feature testing or whatever,Are you aware of the test suite and the auto-tester?My point is that we have no tooling. Project exists, but they all ends up dead at some point or ends up not caring about compatibility that much (I'm aware of at least 3 serious D like projects that dropped dmd compatibility after spending quite a lot of time on it). The situation is really bad in that regard (many stuff are implementation defined, or even not defined at all because the implementation is known to be buggy), and adding surprise, half specified features are really not helping. If you have no idea what my point is, I'm probably wasting my time working on D.Let's not talk these awesome static code analysis tools, java would become jealous.I have no idea what your point is.
Nov 06 2012
On 06/11/12 17:59, deadalnix wrote:Le 06/11/2012 17:46, Walter Bright a écrit :If you mean, we should be working on getting the existing stuff working before we think about adding more stuff, I agree 100%. I would say we're about three years away from it being sensible to work on annotations. It's reasonable to draft a preliminary proposal (A roadmap, what a novel concept!). But I think it would be a big mistake to do much work on it.On 11/6/2012 8:27 AM, deadalnix wrote:If it is the only problem, we have a pandemic spread of hallucinogen trance amongs D users.OK, I may break all the happiness of that news but . . . Tuple in D is notoriously known to be a badly designed feature. Basing more stuff on that just because we have them is short sighted and will only result in D's tuples being broken forever, several tuples implementations for more user confusion, or future major breakage.The only real trouble with tuples is that functions can't return them.Yes, I'm also aware I hit compiler bugs on a daily basis, that my codebase is full of workaround on some of them.We still don't have any scheme for a stable D, feature testing or whatever,Are you aware of the test suite and the auto-tester?My point is that we have no tooling. Project exists, but they all ends up dead at some point or ends up not caring about compatibility that much (I'm aware of at least 3 serious D like projects that dropped dmd compatibility after spending quite a lot of time on it). The situation is really bad in that regard (many stuff are implementation defined, or even not defined at all because the implementation is known to be buggy), and adding surprise, half specified features are really not helping. If you have no idea what my point is, I'm probably wasting my time working on D.Let's not talk these awesome static code analysis tools, java would become jealous.I have no idea what your point is.
Nov 07 2012
Don Clugston, el 7 de November a las 09:23 me escribiste:100% agree. It might make a little sense if it were in an experimental branch for people to try out and find bugs. But it makes no sense to keep adding features to the stable branch, when a release should be made soon, out of the blue like this just because Walter woke up one day with an idea. Seriously Walter, please do some planing and consult with the other developers before committing stuff to the master branch, if you keep treating the language as your own toy. It would be very difficult for people to perceive it as a real open source and community driven project if you keep doing that. -- LucaIf you have no idea what my point is, I'm probably wasting my time working on D.If you mean, we should be working on getting the existing stuff working before we think about adding more stuff, I agree 100%. I would say we're about three years away from it being sensible to work on annotations. It's reasonable to draft a preliminary proposal (A roadmap, what a novel concept!). But I think it would be a big mistake to do much work on it.
Nov 07 2012
Le 07/11/2012 09:23, Don Clugston a écrit :If you mean, we should be working on getting the existing stuff working before we think about adding more stuff, I agree 100%.That is a good part of my point. The other part being that surprise feature dropped in master, not only impair stability, but also impair the ability for developing tooling around D. My problem isn't the feature itself. I'm all for annotation. But the way it is added in the language make nonsense and is even dangerous for D.I would say we're about three years away from it being sensible to work on annotations. It's reasonable to draft a preliminary proposal (A roadmap, what a novel concept!). But I think it would be a big mistake to do much work on it.Exactly. And propose the feature in an experimental branch or something before pushing it to master, so people can test it, it can be refined as needed and 3rd party tool can adapt to it.
Nov 07 2012
Enjoying playing with the new stuff. UDAs appear to work on class, struct and global methods, but not interface methods. Any reason for the omission? Would be great to have them on interface methods too - for example to define COM dispids.
Nov 06 2012
On 11/6/2012 9:07 AM, John Chapman wrote:UDAs appear to work on class, struct and global methods, but not interface methods. Any reason for the omission? Would be great to have them on interface methods too - for example to define COM dispids.Can you show an example code snippet?
Nov 06 2012
On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:On 11/6/2012 9:07 AM, John Chapman wrote:It would save having to read the registry and load type libraries at runtime just to map method names to corresponding IDs. struct dispid { int value; } // WebBrowser event interface to be implemented interface DWebBrowserEvents2 : IDispatch { [dispid(102)] void statusTextChange(); [dispid(108)] void progressChange(); [dispid(105)] void commandStateChange(); /* and so on */ } Then the implementing class maps method names to IDs. mixin template COMDispatch() { int[string] dispIdMap; void delegate()[int] methodMap; this() { // Use __traits to get member names and dispid attributes // from base interfaces and store in dispIdMap. // Then connect up IDs to delegates in methodMap. foreach (T; InterfacesTuple!(typeof(this))) foreach (m; __traits(getMembers, T)) methodMap[dispIdMap[m]] = &mixin(m); } HRESULT GetDispIDsOfNames(wchar** names, int count, int* ids) { // A COM component asks for IDs of our methods. foreach (i; 0 .. count) { ids[i] = dispIdMap.get(names[i].toString(), DISPID_UNKNOWN); } } HRESULT Invoke(int dispId) { // A COM component calls Invoke, and we forward to a method. if (auto m = dispId in methodMap) m(); } } class WebBrowserEventsImpl : DWebBrowserEvents2 { mixin COMDispatch; void statusTextChange() {} void progressChange() {} void commandStateChange() {} }UDAs appear to work on class, struct and global methods, but not interface methods. Any reason for the omission? Would be great to have them on interface methods too - for example to define COM dispids.Can you show an example code snippet?
Nov 06 2012
On 11/6/2012 12:33 PM, John Chapman wrote:On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:I could use a compilable one :-) Yes, I could edit it until it was compilable, but often that makes the problem go away and then there's more back and forth.On 11/6/2012 9:07 AM, John Chapman wrote:It would save having to read the registry and load type libraries at runtime just to map method names to corresponding IDs.UDAs appear to work on class, struct and global methods, but not interface methods. Any reason for the omission? Would be great to have them on interface methods too - for example to define COM dispids.Can you show an example code snippet?
Nov 06 2012
On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:On 11/6/2012 9:07 AM, John Chapman wrote:For further examples on how annotations on interfaces would be useful, see my post about Thrift – services happen to be translated into D interfaces. DavidUDAs appear to work on class, struct and global methods, but not interface methods. Any reason for the omission? Would be great to have them on interface methods too - for example to define COM dispids.Can you show an example code snippet?
Nov 06 2012
Just thinking out loud... [Controller("thing")] [VirtualAction("new", "create", Protect(Role("admin")))] [VirtualAction("edit", "update", Protect(OwnerRelation))] class ThingController : ApplicationController { [Action, Protect(Role("admin"))] void create ( Request req, Response res ) {...} [Action] void index ( Request req, Response res ) {...} [Action, Protect(Role("member"))] void show ( Request req, Response res ) {...} [Action, Protect(OwnerRelation)] void update ( Request req, Response res ) {...} [Action("delete"), Protect(Role("admin"))] void remove ( Request req, Response res ) {...} } [Model("thing")] [ForbidMassAssignment] class Thing : Model { [Attr, Shallow] [Validate( Present, Unique, Length("<=", 128) )] A!string name; [Attr, Shallow] [Validate( Length("[]", 16, 256) )] A!string description; [Attr(BelongsTo, User), Shallow] [Validate( Present )] A!User user; [Attr(HasMany, Tag, Through(Tagging))] [Validate( NoDuplicate )] A!(Tagging[]) tags; [Attr] [Validate( Present )] A!ulong size; [Attr] [Validate( Present )] A!ulong weight; property ulong ratio () {...} } My mind reels... -- Chris Nicholson-Sauls
Nov 06 2012
On Monday, November 05, 2012 23:55:49 Walter Bright wrote:UDA's can be extracted into an expression tuple using __traits: [ 'c' ] string s; pragma(msg, __traits(getAttributes, s)); prints: tuple('c') If there are no user defined attributes for the symbol, an empty tuple is returned. The expression tuple can be turned into a manipulatable tuple: template Tuple(T...) { alias T Tuple; }Wait. That's a TypeTuple. Tuple is completely different. You're going to create serious confusion here if you call it Tuple. Tuple is in std.typecons. And we've already seriously discussed renaming TypeTuple to something else because it doesn't hold just types and because it really doesn't act like a tuple (if it were really a tuple, it wouldn't auto-expand). The idea here may be good, but the terminology used is going to cause a lot of confusion. - Jonathan M Davis
Nov 06 2012
New version up now with a couple reported problems with UDA fixed.
Nov 07 2012
On Wednesday, 7 November 2012 at 08:41:48 UTC, Walter Bright wrote:New version up now with a couple reported problems with UDA fixed.I may have found a little glitch...? mixin("[1] int a;"); ["[2] int b;"] int c; mixin(__traits(getAttributes, c)[0]); pragma(msg, __traits(getAttributes, a)); => tuple() pragma(msg, __traits(getAttributes, b)); => tuple() The use-case for this is parsing a foreign language which will be compiled to mixed in d-code.
Nov 08 2012
First of all: Awesome. Secondly: Fastest-growing thread ever? ;)
Nov 07 2012
On Wednesday, November 07, 2012 16:45:20 Nick Sabalausky wrote:First of all: Awesome. Secondly: Fastest-growing thread ever? ;)In Announce? Probably. In all of the D groups? Probably not. There have been some _very_ active threads in the main newsgroup. This thread is quite tame in comparison to a number of them. It _is_ very active though. - Jonathan M Davis
Nov 07 2012
On 11/7/2012 1:45 PM, Nick Sabalausky wrote:First of all: Awesome. Secondly: Fastest-growing thread ever? ;)The historical UDA threads have been large, too.
Nov 07 2012
Awesome. Lack of UDA has really caused some very ugly workarounds in my code, and it's really nice to see that it's being solved now. Probably one of the most important missing features I've encountered. I do agree however with preventing any built-in types / literals being used as an annotation. It's just not safe, completely goes around the module system, and is abused in the same way as it are classes derived from Attribute. This makes things a bit more obvious, allows a common base type (probably not needed in D because it's done at compile-time), but is rather hackish in my opinion (plus, in D you may want structs as attributes?). I definitely would like to see something like the attribute suggestion though. Using types not meant to be used as attributes as attributes is dangerous and leads to conflicts when people want it to mean different things. What does ' Vector3f(1, 1, 1) int a' even mean? What if people use it to mean different things? It's just as confusing as ' 3 int a'.
Nov 07 2012
On 11/7/2012 3:06 PM, Kapps wrote:I do agree however with preventing any built-in types / literals being used as an annotation. It's just not safe, completely goes around the module system, and example, all attributes are classes derived from Attribute. This makes things a bit more obvious, allows a common base type (probably not needed in D because it's done at compile-time), but is rather hackish in my opinion (plus, in D you may want structs as attributes?). I definitely would like to see something like the attribute suggestion though. Using types not meant to be used as attributes as attributes is dangerous and leads to conflicts when people want it to mean different things. What does ' Vector3f(1, 1, 1) int a' even mean? What if people use it to mean different things? It's just as confusing as ' 3 int a'.See new thread I started on this in digitalmars.D.
Nov 07 2012