www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - User Defined Attributes

reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "Tove" <tove fransson.se> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent "Max Samukha" <maxsamukha gmail.com> writes:
On Tuesday, 6 November 2012 at 08:20:42 UTC, Walter Bright wrote:
 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.
Thank you. Now we can stop connecting the dots with hidden declaration hacks. Yay!
Nov 06 2012
prev sibling next sibling parent reply =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
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
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 12:20 AM, Sönke Ludwig wrote:> 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 '[]'
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
next sibling parent reply =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
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 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 '[]'
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.
Definitely! Thanks a lot for tackling this, to me this seems like something that can get a real killer feature for the language!
Nov 06 2012
parent "alex" <info alexanderbothe.com> writes:
On Tuesday, 6 November 2012 at 08:55:06 UTC, Sönke Ludwig wrote:
 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 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 '[]'
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.
Definitely! Thanks a lot for tackling this, to me this seems like something that can get a real killer feature for the language!
test void myUnittest() { } Uh yeah, that would be awesome!
Nov 06 2012
prev sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 10:10 AM, Jacob Carlborg wrote:
 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?
Because I still think in a linear fashion :-)
Nov 06 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent "xenon325" <1 a.net> writes:
On Tuesday, 6 November 2012 at 18:49:22 UTC, Walter Bright wrote:
 On 11/6/2012 10:10 AM, Jacob Carlborg wrote:
 Walter, why aren't you using branches for these kind of things?
Because I still think in a linear fashion :-)
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/gitflow
Nov 06 2012
prev sibling parent "kris" <kris theredhead.nl> writes:
On Tuesday, 6 November 2012 at 18:49:22 UTC, Walter Bright wrote:
 On 11/6/2012 10:10 AM, Jacob Carlborg wrote:
 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?
Because I still think in a linear fashion :-)
hehe, how on earth were you able to come up with D in the first place then? ;-p
Sep 03 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-06 16:39, Walter Bright wrote:
 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.
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 Carlborg
Nov 06 2012
next sibling parent =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
Am 06.11.2012 16:55, schrieb Jacob Carlborg:
 On 2012-11-06 16:39, Walter Bright wrote:
 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.
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;
+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.
Nov 06 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 7:55 AM, Jacob Carlborg wrote:
 On 2012-11-06 16:39, Walter Bright wrote:
 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.
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;
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
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-06 17:04, Walter Bright wrote:

 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;
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.
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 Carlborg
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 19:19, Jacob Carlborg a écrit :
 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.
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).
Nov 06 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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.

 David
Oh, didn't notice until now. I've already added my vote. -- /Jacob Carlborg
Nov 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jacob Carlborg" <doob me.com> wrote in message 
news:k7bp22$1rsc$3 digitalmars.com...
 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
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.
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 7:52 PM, bearophile wrote:
 Walter Bright:

 But I'm not sure at this point if that is the right thing to do.
Why?
D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.
 [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
next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent reply Leandro Lucarella <luca llucax.com.ar> writes:
Walter Bright, el  6 de November a las 20:19 me escribiste:
 On 11/6/2012 7:52 PM, bearophile wrote:
Walter Bright:

But I'm not sure at this point if that is the right thing to do.
Why?
D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.
What? UDAs has been for quite a long time out in the wild, just not in C++.
[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.
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). --
Nov 07 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 07, 2012 13:01:52 Jacob Carlborg wrote:
 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;
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 Davis
Nov 07 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 07/11/2012 13:01, Jacob Carlborg a écrit :
 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;
Yes that was pretty close to what my proposal looked like in the big annotation thread, except I used ttribute .
Nov 07 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply deadalnix <deadalnix gmail.com> writes:
Le 07/11/2012 21:35, Walter Bright a écrit :
 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.
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.
Nov 07 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-11-07 21:38, deadalnix wrote:

 Adding a whole new aggregate type is a pretty intrusive and major change.
Is it? Just have it behave as a struct or class. But I guess the suggestion below is just as good.
 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
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 07/11/2012 23:20, Walter Bright a écrit :
 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.
Java is mostly compile time (and optionally runtime). See http://projectlombok.org/ for what can be done at compile time with attributes + compiler hooks.
 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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 08/11/2012 00:17, Walter Bright a écrit :
 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?
The hook is associated to a given attribute so no it doesn't.
Nov 07 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/7/2012 4:12 PM, deadalnix wrote:
 Le 08/11/2012 00:17, Walter Bright a écrit :
 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?
The hook is associated to a given attribute so no it doesn't.
Yes, that makes the attribute global.
Nov 07 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/7/2012 11:27 PM, Jacob Carlborg wrote:
 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.
A plugin would apply globally, wouldn't it?
Nov 08 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/8/2012 4:37 AM, Jacob Carlborg wrote:
 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
I believe that does have the essential effect of making the attribute global.
Nov 08 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/8/2012 12:00 PM, Jacob Carlborg wrote:
 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.
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.
Nov 08 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 08/11/2012 11:56, Walter Bright a écrit :
 On 11/7/2012 11:27 PM, Jacob Carlborg wrote:
 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.
A plugin would apply globally, wouldn't it?
No it would apply on symbols qualified with a given attribute (provided by the plugin).
Nov 09 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/9/2012 6:28 PM, deadalnix wrote:
 Le 08/11/2012 11:56, Walter Bright a écrit :
 On 11/7/2012 11:27 PM, Jacob Carlborg wrote:
 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.
A plugin would apply globally, wouldn't it?
No it would apply on symbols qualified with a given attribute (provided by the plugin).
Meaning a given attribute can have only one, global, meaning.
Nov 09 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Nov 10 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/10/2012 11:15 AM, Jacob Carlborg wrote:
 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?
That is what I mean, and it also applies to a library type which different modules may press into service as attributes.
Nov 13 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/13/2012 11:16 PM, Jacob Carlborg wrote:
 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.
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.
Nov 13 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/14/12 1:13 PM, Walter Bright wrote:
 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.
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. Andrei
Nov 14 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/15/2012 12:22 AM, Jacob Carlborg wrote:
 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.
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
next sibling parent reply "Tove" <tove fransson.se> writes:
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
parent "David Nadlinger" <see klickverbot.at> writes:
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:
 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.
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(…)). David
Nov 16 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-11-16 11:41, Walter Bright wrote:

 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.
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 don't know what to say anymore. I can only repeat what I've already said. This conversion has clearly gone into circles. -- /Jacob Carlborg
Nov 16 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 14/11/2012 22:13, Walter Bright a écrit :
 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.
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.
Nov 16 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/13/2012 2:55 PM, bearophile wrote:
 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.
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.
Nov 13 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent "bearophile" <bearophileHUGS lycos.com> writes:
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
prev sibling parent reply Leandro Lucarella <luca llucax.com.ar> writes:
Walter Bright, el 13 de November a las 16:49 me escribiste:
 On 11/13/2012 2:55 PM, bearophile wrote:
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.
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.
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. --
Nov 14 2012
next sibling parent reply "Tove" <tove fransson.se> writes:
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
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-14 12:18, Tove wrote:
 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...
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 Carlborg
Nov 14 2012
parent reply "Tove" <tove fransson.se> writes:
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
parent reply Leandro Lucarella <luca llucax.com.ar> writes:
Tove, el 14 de November a las 13:55 me escribiste:
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; }
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; } --
Nov 14 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/14/2012 03:31 PM, Leandro Lucarella wrote:
 Tove, el 14 de November a las 13:55 me escribiste:
 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; }
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? ...
By not telling it that they are for it. Note that the [thrift.attributes.Definition] annotation is significant.
 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
parent Leandro Lucarella <luca llucax.com.ar> writes:
Timon Gehr, el 14 de November a las 17:25 me escribiste:
 On 11/14/2012 03:31 PM, Leandro Lucarella wrote:
Tove, el 14 de November a las 13:55 me escribiste:
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; }
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? ...
By not telling it that they are for it. Note that the [thrift.attributes.Definition] annotation is significant.
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?
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; } }
I don't know what does this mean. --
Nov 15 2012
prev sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent reply "Tove" <tove fransson.se> writes:
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:
 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
// 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 ...
Nov 14 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
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
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
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
prev sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent reply "Tove" <tove fransson.se> writes:
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?

 David
I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.
Nov 15 2012
parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent "Tove" <tove fransson.se> writes:
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:
 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
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.
Nov 16 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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
 types
One 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
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 13/11/2012 23:27, Walter Bright a écrit :
 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).
I presented you compile time uses cases for such a mecanism already. See project lombok for instance.
 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
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 10/11/2012 05:02, Walter Bright a écrit :
 On 11/9/2012 6:28 PM, deadalnix wrote:
 Le 08/11/2012 11:56, Walter Bright a écrit :
 On 11/7/2012 11:27 PM, Jacob Carlborg wrote:
 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.
A plugin would apply globally, wouldn't it?
No it would apply on symbols qualified with a given attribute (provided by the plugin).
Meaning a given attribute can have only one, global, meaning.
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.
Nov 10 2012
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
started a new thread on this over in digitalmars.D
Nov 07 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
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
next sibling parent "Max Samukha" <maxsamukha gmail.com> writes:
On Thursday, 8 November 2012 at 09:08:23 UTC, Max Samukha wrote:
     alias getAttribute!(b, foo) t;
Ignore that line.
Nov 08 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Thursday, 8 November 2012 at 12:42:38 UTC, Jacob Carlborg 
wrote:
 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.
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.
Nov 08 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 07/11/2012 05:19, Walter Bright a écrit :
 On 11/6/2012 7:52 PM, bearophile wrote:
 Walter Bright:

 But I'm not sure at this point if that is the right thing to do.
Why?
D was fortunate in having 10 years of experience with C++'s exception system to learn from. We don't have that with UDAs.
 [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.
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.
 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
prev sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Walter Bright" <newshound2 digitalmars.com> wrote in message 
news:k7cko9$hes$1 digitalmars.com...
 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.
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.
Nov 06 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/07/2012 08:08 AM, Daniel Murphy wrote:
 "Walter Bright" <newshound2 digitalmars.com> wrote in message
 news:k7cko9$hes$1 digitalmars.com...
 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.
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 {}
Then what does this particular restriction buy?
 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
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 07/11/2012 10:13, Timon Gehr a écrit :
 On 11/07/2012 08:08 AM, Daniel Murphy wrote:
 "Walter Bright" <newshound2 digitalmars.com> wrote in message
 news:k7cko9$hes$1 digitalmars.com...
 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.
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 {}
Then what does this particular restriction buy?
 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; }})));
I'd argue that is expression is the problem here, not really the annotation.
Nov 07 2012
prev sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:k7d8n1$1o69$1 digitalmars.com...
 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?
It makes it harder to do the wrong thing.
Nov 07 2012
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-39-06 20:11, Jacob Carlborg <doob me.com> wrote:

 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 =C2=BBglobal=C2=AB) as annotations needs to be explicit=
ly =
 discouraged.
Then why allow it in the first place?
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. -- = Simen
Nov 07 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 17:37, Walter Bright a écrit :
 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,
Not with UFCS.
Nov 06 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 9:01 AM, deadalnix wrote:
 Le 06/11/2012 17:37, Walter Bright a écrit :
 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,
Not with UFCS.
You have a point.
Nov 06 2012
prev sibling next sibling parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 12:39 AM, Jakob Ovrum wrote:> 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.
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).
Nov 06 2012
next sibling parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
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
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
parent dennis luehring <dl.soluz gmx.net> writes:
Am 06.11.2012 10:04, schrieb Jakob Ovrum:
 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.
ok not you - but many others
Nov 06 2012
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 8:04 AM, Johannes Pfau wrote:> 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.
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
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
prev sibling parent deadalnix <deadalnix gmail.com> writes:
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
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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:
 -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.
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.
Nov 06 2012
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
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
prev sibling parent =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
Am 06.11.2012 09:39, schrieb Jakob Ovrum:
 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. 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.
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.
Nov 06 2012
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
 snip
Nice to hear because it was unexpected and was requested prevously by community.
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 12:49 AM, Maxim Fomin wrote:
 On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
 snip
Nice to hear because it was unexpected and was requested prevously by community.
I've been intending to do it for a while now.
Nov 06 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, November 06, 2012 01:06:49 Walter Bright wrote:
 On 11/6/2012 12:49 AM, Maxim Fomin wrote:
 On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
 snip
Nice to hear because it was unexpected and was requested prevously by community.
I've been intending to do it for a while now.
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 Davis
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 22:49, Walter Bright a écrit :
 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.
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.
Nov 06 2012
prev sibling next sibling parent reply "Jonas Drewsen" <nospam4321 hotmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.

 /Jonas
Yes, you can attach them to other symbols, including user defined types.
Nov 06 2012
parent "Jonas Drewsen" <nospam4321 hotmail.com> writes:
On Tuesday, 6 November 2012 at 09:08:25 UTC, Walter Bright wrote:
 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.

 /Jonas
Yes, you can attach them to other symbols, including user defined types.
Great. Can't wait to play around with this. I think project Orange could really take advantage of this. /Jonas
Nov 06 2012
prev sibling next sibling parent reply Jens Mueller <jens.k.mueller gmx.de> writes:
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=3D
 User Defined Attributes
 -----------------------
=20
 User Defined Attributes (UDA) are compile time expressions that can be at=
tached
 to a declaration. These attributes can then be queried, extracted, and ma=
nipulated
 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 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 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.
=20
 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.
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
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
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?

 Jens
In 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
prev sibling next sibling parent reply Jens Mueller <jens.k.mueller gmx.de> writes:
Jens Mueller wrote:
 Walter Bright wrote:
 References:
=20
 http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_a=
gain_163042.html
=20
 http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_pr=
oposal_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=3D
 User Defined Attributes
 -----------------------
=20
 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.
=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=
nated:
=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 =
variable:
=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=
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.
=20
 Whether the attributes are values or types is up to the user, and wheth=
er later
 attributes 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?
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. Jens
Nov 06 2012
parent reply "Tove" <tove fransson.se> writes:
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
parent "simendsjo" <simendsjo gmail.com> writes:
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
prev sibling next sibling parent reply "Max Samukha" <maxsamukha gmail.com> writes:
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
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 4:18 AM, Max Samukha wrote:
 Attributes on overloads are critical. Currently fails:
Found & fixed. Thanks!
Nov 06 2012
prev sibling next sibling parent reply "angel" <andrey.gelman gmail.com> writes:
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
parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
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")] foo
Right, 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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-06 16:15, Walter Bright wrote:

 enum test = "test";

 [test] void foo () {}
or: enum EEE; [EEE] void foo() { }
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 Carlborg
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 7:31 AM, Jacob Carlborg wrote:
 On 2012-11-06 16:15, Walter Bright wrote:

 enum test = "test";

 [test] void foo () {}
or: enum EEE; [EEE] void foo() { }
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.
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.
Nov 06 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
next sibling parent reply Rory McGuire <rjmcguire gmail.com> writes:
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
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
parent reply "Gor Gyolchanyan" <gor.f.gyolchanyan gmail.com> writes:
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:
 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.
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!!! :-)
Nov 06 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 8:47 AM, bearophile wrote:
 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.
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.)
 User defined attributes cannot invent new semantics for the language.
Right, that's my point :-)
So it cannot work for the use case you suggested. I'm still asking for a compelling use case.
 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.
I don't see how having the user add a UDA is better than having the user add "const".
Nov 06 2012
next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 06.11.2012 18:32, schrieb David Nadlinger:
 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) }
perfect example - thx alot
Nov 06 2012
prev sibling next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 06.11.2012 18:32, schrieb David Nadlinger:
 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:
http://svn.apache.org/repos/asf/thrift/trunk/tutorial/tutorial.thrift
Nov 06 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
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
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 9:32 AM, David Nadlinger wrote:
 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«.
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.
 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
parent reply "David Nadlinger" <see klickverbot.at> writes:
On Tuesday, 6 November 2012 at 17:51:28 UTC, Walter Bright wrote:
 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 has type i32?
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. David
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 10:01 AM, David Nadlinger wrote:> On Tuesday, 6 November 2012 at 
17:51:28 UTC, Walter Bright wrote:
 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 has type i32?
It means that ›a‹ has type i32
Ok, but a type is not a UDA <g>.
 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
parent "David Nadlinger" <see klickverbot.at> writes:
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:
 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 has
type i32?
 It means that ›a‹ has type i32
Ok, but a type is not a UDA <g>.
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. ;)
 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
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent "bearophile" <bearophileHUGS lycos.com> writes:
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.

 // 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.
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
Nov 06 2012
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
parent Walter Bright <newshound2 digitalmars.com> writes:
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:
   [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.
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.
Nov 06 2012
prev sibling next sibling parent Paulo Pinto <pjmlp progtools.org> writes:
Am 06.11.2012 17:41, schrieb Walter Bright:
 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.
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. -- Paulo
Nov 06 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/06/2012 05:41 PM, Walter Bright wrote:
 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. ...
The use cases are the same as for other declarations. Parameter declarations are not special.
Nov 06 2012
prev sibling next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
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. to have this at compiletime available by using UDAs on parameters + an compiletime generator would be absolutely briliant my vote +1 for UDAs on parameters
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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. I don't know what use UDAs would be for parameters.
Nov 06 2012
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
prev sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
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 generator
 I 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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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 generator
But 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
parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 06.11.2012 17:50, schrieb Walter Bright:
 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 generator
But 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).
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)
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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 method
Has 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
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 06.11.2012 18:14, schrieb Walter Bright:> 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 method
Has this capability ever been used?
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++ :(
Nov 06 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 18:14, Walter Bright a écrit :
 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 method
Has 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.
It remove complexity in the sens it remove special cases. It indeed add complexity for the compiler.
Nov 06 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/06/2012 06:31 PM, deadalnix wrote:
 Le 06/11/2012 18:14, Walter Bright a écrit :
 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 method
Has 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.
It remove complexity in the sens it remove special cases. It indeed add complexity for the compiler.
But almost none. It is easy to get right.
Nov 06 2012
prev sibling next sibling parent reply "Tove" <tove fransson.se> writes:
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:
 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)); }
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 statement
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply "Tove" <tove fransson.se> writes:
On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:
 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.
Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 8:02 AM, Tove wrote:
 On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:
 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.
Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;
I have no idea how you could make that work.
Nov 06 2012
parent Paulo Pinto <pjmlp progtools.org> writes:
Am 06.11.2012 17:26, schrieb Walter Bright:
 On 11/6/2012 8:02 AM, Tove wrote:
 On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:
 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.
Hmm, what about library based GC annotations? ["GC.NoScan"] int* local_p;
I have no idea how you could make that work.
I can only see it work if the runtime is aware of magic annotations, which are kept in the binary. -- Paulo
Nov 06 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply deadalnix <deadalnix gmail.com> writes:
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.
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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't work like regular declarations, never have, and I don't know of a language where they do. They even have a different grammar.
Nov 06 2012
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
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't
 work like regular declarations, never have, and I don't know of a 
language where
 they 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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 19:02, Walter Bright a écrit :
 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."
No. It is needed to annotate symbols, uses cases are numerous. Now, if an exception is added, the exception should be justified.
Nov 06 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/06/2012 07:02 PM, Walter Bright wrote:
 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." ...
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.
Nov 06 2012
parent "Max Samukha" <maxsamukha gmail.com> writes:
On Tuesday, 6 November 2012 at 20:41:27 UTC, Timon Gehr wrote:
 On 11/06/2012 07:02 PM, Walter Bright wrote:
 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." ...
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.
Exactly. Looking forward to complaints about impossibility to annotate module declarations.
Nov 06 2012
prev sibling parent reply "Max Samukha" <maxsamukha gmail.com> writes:
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 :
 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't work like regular declarations, never have, and I don't know of a language where they do. They even have a different grammar.
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.
Nov 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 11:42 AM, Max Samukha wrote:> 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?
Not a problem, as you'd search the tuple for the attribute that matters anyway.
Nov 06 2012
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
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 both
 on 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.
By "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?
Nov 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent "Max Samukha" <maxsamukha gmail.com> writes:
On Tuesday, 6 November 2012 at 20:49:07 UTC, Walter Bright wrote:
 On 11/6/2012 12:28 PM, Max Samukha wrote:

 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.
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.
Nov 06 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent "Max Samukha" <maxsamukha gmail.com> writes:
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
prev sibling next sibling parent reply "nazriel" <spam dzfl.pl> writes:
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
I 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
parent Walter Bright <newshound2 digitalmars.com> writes:
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 Phobos
The auto tester shows it's working. http://d.puremagic.com/test-results/
Nov 06 2012
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply deadalnix <deadalnix gmail.com> writes:
Le 06/11/2012 17:46, Walter Bright a écrit :
 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.
If it is the only problem, we have a pandemic spread of hallucinogen trance amongs D users.
 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?
Yes, I'm also aware I hit compiler bugs on a daily basis, that my codebase is full of workaround on some of them.
 Let's not talk these awesome static code analysis tools, java would
 become jealous.
I have no idea what your point is.
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.
Nov 06 2012
parent reply Don Clugston <dac nospam.com> writes:
On 06/11/12 17:59, deadalnix wrote:
 Le 06/11/2012 17:46, Walter Bright a écrit :
 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.
If it is the only problem, we have a pandemic spread of hallucinogen trance amongs D users.
 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?
Yes, I'm also aware I hit compiler bugs on a daily basis, that my codebase is full of workaround on some of them.
 Let's not talk these awesome static code analysis tools, java would
 become jealous.
I have no idea what your point is.
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.
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
next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Don Clugston, el  7 de November a las 09:23 me escribiste:
If 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.
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. -- Luca
Nov 07 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
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
prev sibling next sibling parent reply "John Chapman" <johnch_atms hotmail.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply "John Chapman" <johnch_atms hotmail.com> writes:
On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:
 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?
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() {} }
Nov 06 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/6/2012 12:33 PM, John Chapman wrote:
 On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:
 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?
It would save having to read the registry and load type libraries at runtime just to map method names to corresponding IDs.
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.
Nov 06 2012
prev sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Tuesday, 6 November 2012 at 17:20:10 UTC, Walter Bright wrote:
 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?
For further examples on how annotations on interfaces would be useful, see my post about Thrift – services happen to be translated into D interfaces. David
Nov 06 2012
prev sibling next sibling parent "Chris Nicholson-Sauls" <ibisbasenji gmail.com> writes:
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
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
New version up now with a couple reported problems with UDA fixed.
Nov 07 2012
parent "Tove" <tove fransson.se> writes:
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
prev sibling next sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
First of all: Awesome.

Secondly: Fastest-growing thread ever? ;)
Nov 07 2012
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling parent reply "Kapps" <opantm2+spam gmail.com> writes:
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
parent Walter Bright <newshound2 digitalmars.com> writes:
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