www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - So, User-Defined Attributes

reply "Philippe Sigaud" <philippe.sigaud gmail.com> writes:
OK, now that 2.061 is out, we have User-Defined Attributes (UDAs).

Except, there is no doc on them, no explanation, nothing. For 
people who did not follow the monstrous threads in November, it's 
as if UDA do not exist.

Myself, I upgraded from 2.060 only yesterday, and I never used 
them. Heck, I do not even know their syntax. This thread is for 
people like me, who wonder what UDA are, and what can be done 
with them.

Jacob Carlborg wrote documentation, but it's not merged into 
dlang.org yet, AFAICT. Here it is:

https://github.com/jacob-carlborg/d-programming-language.org/commit/bddbdf18353203ba12d8e0e44391e8b6a031b91a

Here is the executive summary:

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.

Syntax:

 (3) int a;
 ("string", 7) int b;

enum Foo;
 Foo int c;

struct Bar
{
     int x;
}

 Bar(3) int d;


 From that, I get we can put any CT symbol (even a value) as an 
attribute. I thought we were restricted to user defined types.

To query them, use __traits(getAttributes, symbol)


 ('c') string s;
__traits(getAttributes, s)

this gives a tuple of attributes, that can be manipulated as a 
template tuple parameter (the 'raw' tuples).



Jacob, you doc says UDA are (grammatically) treated as storage 
classes. Can we do:

class C {
      (3, "hello"):
         int a;
         double d;
}

And get both a and d with the same UDAs?
[Answer: silly me, I have 2.061. Yes, that works, both C.a and 
C.d have (3, "hello") as an attribute]

My own rapid reading tells me we will rapidly need good tuple 
manipulations templates in Phobos. We have mapping and filtering 
(I guess?), but overloading, discarding, dropping and folding 
will be needed also.
Jan 04 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-04 16:45, Philippe Sigaud wrote:
 OK, now that 2.061 is out, we have User-Defined Attributes (UDAs).

 Except, there is no doc on them, no explanation, nothing. For people who
 did not follow the monstrous threads in November, it's as if UDA do not
 exist.

 Myself, I upgraded from 2.060 only yesterday, and I never used them.
 Heck, I do not even know their syntax. This thread is for people like
 me, who wonder what UDA are, and what can be done with them.

 Jacob Carlborg wrote documentation, but it's not merged into dlang.org
 yet, AFAICT. Here it is:

 https://github.com/jacob-carlborg/d-programming-language.org/commit/bddbdf18353203ba12d8e0e44391e8b6a031b91a
And here, nicely rendered: https://dl.dropbox.com/u/18386187/attribute.html#uda There's also documentation for the Traits section but nothing which isn't available on the Attribute section. -- /Jacob Carlborg
Jan 04 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-04 16:45, Philippe Sigaud wrote:

 Syntax:

  (3) int a;
  ("string", 7) int b;

 enum Foo;
  Foo int c;

 struct Bar
 {
      int x;
 }

  Bar(3) int d;


  From that, I get we can put any CT symbol (even a value) as an
 attribute. I thought we were restricted to user defined types.
No, basically anything that can be put in a tuple can be used as an UDA. I'm wondering if we want to add a meta attribute to Phobos or druntime (object.d). Some thing like: enum attribute; attribute struct Foo { } Now, by convention "Foo" is an attribute and should only be used as an attribute. We could also add some functions to std.traits for querying UDA that takes advantage of this attribute. -- /Jacob Carlborg
Jan 04 2013
prev sibling next sibling parent "Max Samukha" <maxsamukha gmail.com> writes:
On Friday, 4 January 2013 at 15:45:21 UTC, Philippe Sigaud wrote:
 My own rapid reading tells me we will rapidly need good tuple 
 manipulations templates in Phobos.
s/we will rapidly need/we have needed for years
Jan 04 2013
prev sibling next sibling parent reply "Philippe Sigaud" <philippe.sigaud gmail.com> writes:
So, I'm testing how to transfer UDA from one symbol to another.

```
auto transferAttributes(alias origin, To)(To t)
{
      (__traits(getAttributes, origin)) To temp = t;
     pragma(msg, __traits(getAttributes, temp));
     return temp;
}

void main()
{
      (3, "hello") int i = 10;
     writeln("[",__traits(getAttributes, i), "]");

     double d = 3.14;
     auto d2 = transferAttributes!(i)(d);
     // Doesn't work
     writeln("[",__traits(getAttributes, d2), "]");

     // Works:
      (__traits(getAttributes, i)) double d3 = 3.14;
     writeln("[",__traits(getAttributes, d3), "]");
}
```

Begins at the end: d3 (a double) indeed ends up as having i (an 
int) attributes. All is well and good.

But transferAttributes does not work: inside its scope, temp has 
the attributes from origin, but not when it gets out.

Also, dropping the auto return is not accepted by the compiler, 
even though it seems natural for me:

 (__traits(getAttributes, origin)) To transferAttributes(alias 
origin, To)(To t)
{
      (__traits(getAttributes, origin)) To temp = t;
...

'origin' is a template parameter and should be reachable to 
determine the return type.
Jan 04 2013
next sibling parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Friday, 4 January 2013 at 16:04:59 UTC, Philippe Sigaud wrote:
 So, I'm testing how to transfer UDA from one symbol to another.

 ```
 auto transferAttributes(alias origin, To)(To t)
 {
      (__traits(getAttributes, origin)) To temp = t;
     pragma(msg, __traits(getAttributes, temp));
     return temp;
 }

 void main()
 {
      (3, "hello") int i = 10;
     writeln("[",__traits(getAttributes, i), "]");

     double d = 3.14;
     auto d2 = transferAttributes!(i)(d);
transferAttributes attaches the attributes to the local declaration. I'd be surprised if they were copied to the outer declaration. Or did you mean attributing the return *type*?
     // Doesn't work
     writeln("[",__traits(getAttributes, d2), "]");

     // Works:
      (__traits(getAttributes, i)) double d3 = 3.14;
     writeln("[",__traits(getAttributes, d3), "]");
 }
 ```

 Begins at the end: d3 (a double) indeed ends up as having i (an 
 int) attributes. All is well and good.

 But transferAttributes does not work: inside its scope, temp 
 has the attributes from origin, but not when it gets out.

 Also, dropping the auto return is not accepted by the compiler, 
 even though it seems natural for me:

  (__traits(getAttributes, origin)) To transferAttributes(alias 
 origin, To)(To t)
 {
      (__traits(getAttributes, origin)) To temp = t;
 ...

 'origin' is a template parameter and should be reachable to 
 determine the return type.
That's a bug. Anyway, you are attributing the function declaration here, not the return type, which is another problem as it looks we do not have a syntax for that and "auto" is required: auto foo() { attr struct S {} return S.init; }
Jan 04 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Max:

 transferAttributes attaches the attributes to the local declaration. I'd
 be surprised if they were copied to the outer declaration. Or did you mean
 attributing the return *type*?
The declaration. The type, I guess I'd use an alias. Though, I guess the alias syntax limitations would probably forbid that. So yes, the local declaration is attributed, that works. How do I propagate the attribute to the returned value? Also, dropping the auto return is not accepted by the compiler, even though
 it seems natural for me:

  (__traits(getAttributes, origin)) To transferAttributes(alias origin,
 To)(To t)
 {
      (__traits(getAttributes, origin)) To temp = t;
 ...

 'origin' is a template parameter and should be reachable to determine the
 return type.
That's a bug.
Already filed?
 Anyway, you are attributing the function declaration here, not the return
 type
Hmm. Would (attr) { ReturnType } functionName (...) work?
 , which is another problem as it looks we do not have a syntax for that
 and "auto" is required:

 auto foo()
 {
      attr struct S {}
     return S.init;
 }
Jan 04 2013
parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Friday, 4 January 2013 at 17:11:04 UTC, Philippe Sigaud wrote:
 The declaration. The type, I guess I'd use an alias. Though, I 
 guess the
 alias syntax limitations would probably forbid that.

 So yes, the local declaration is attributed, that works. How do 
 I propagate
 the attribute to the returned value?
I think you cannot.
 Also, dropping the auto return is not accepted by the compiler, 
 even though
 it seems natural for me:

  (__traits(getAttributes, origin)) To 
 transferAttributes(alias origin,
 To)(To t)
 {
      (__traits(getAttributes, origin)) To temp = t;
 ...

 'origin' is a template parameter and should be reachable to 
 determine the
 return type.
That's a bug.
Already filed?
Don't think so.
 Anyway, you are attributing the function declaration here, not 
 the return
 type
Hmm. Would (attr) { ReturnType } functionName (...) work?
It looks we simply cannot modify existing declarations with UDAs. (attr) alias foo = bar; // (attr) is ignored. It is inconsistent with builtin attributes, which can create modified declarations out of existing ones. I am not sure whether it is a real problem.
Jan 04 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2013 9:48 AM, Max Samukha wrote:
 It looks we simply cannot modify existing declarations with UDAs.

  (attr) alias foo = bar; //  (attr) is ignored.
alias provides a way to provide an alternate name for a symbol. It wouldn't be an alternate name if it had different attributes. Trying to make such work would have serious semantic consequences. Hence, no, you cannot use alias to modify the attributes.
Jan 04 2013
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Jan 4, 2013 at 9:40 PM, Walter Bright <newshound2 digitalmars.com>wrote:

 On 1/4/2013 9:48 AM, Max Samukha wrote:

 It looks we simply cannot modify existing declarations with UDAs.

  (attr) alias foo = bar; //  (attr) is ignored.
alias provides a way to provide an alternate name for a symbol. It wouldn't be an alternate name if it had different attributes. Trying to make such work would have serious semantic consequences. Hence, no, you cannot use alias to modify the attributes.
The (future) documentation says attributes can be used with declarations. I tried to use one before a module declaration but it didn't work. Is that a bug or are module declarations not 'real' declarations?
Jan 04 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2013 12:49 PM, Philippe Sigaud wrote:
 Is that a bug or are module declarations not 'real' declarations?
Module declarations aren't declarations.
Jan 04 2013
next sibling parent "Max Samukha" <maxsamukha gmail.com> writes:
On Friday, 4 January 2013 at 20:58:42 UTC, Walter Bright wrote:
 On 1/4/2013 12:49 PM, Philippe Sigaud wrote:
 Is that a bug or are module declarations not 'real' 
 declarations?
Module declarations aren't declarations.
They conceptually are.
Jan 04 2013
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Jan 4, 2013 at 9:58 PM, Walter Bright <newshound2 digitalmars.com>wrote:

 Module declarations aren't declarations.
Great quote :)
Jan 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/04/2013 11:43 PM, Philippe Sigaud wrote:
 On Fri, Jan 4, 2013 at 9:58 PM, Walter Bright
 <newshound2 digitalmars.com <mailto:newshound2 digitalmars.com>> wrote:


     Module declarations aren't declarations.


 Great quote :)
Walter often argues in terms of DMD implementation details. ... struct ModuleDeclaration { Identifier *id; ...
Jan 06 2013
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Jan 4, 2013 at 9:58 PM, Walter Bright

 <newshound2 digitalmars.com
<mailto:newshound2 **digitalmars.com<newshound2 digitalmars.com>>>
 wrote:


     Module declarations aren't declarations.


 Great quote :)
Walter often argues in terms of DMD implementation details. ... struct ModuleDeclaration { Identifier *id; ... Too low-level, I suppose ;) What he said is also true from the grammar
PoV. It's just funny expressed that way. I keep forgetting modules are not first-class in D (it's not a criticism, I don't what I'd do with first-class modules)
Jan 06 2013
prev sibling parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Friday, 4 January 2013 at 20:40:39 UTC, Walter Bright wrote:
 On 1/4/2013 9:48 AM, Max Samukha wrote:
 It looks we simply cannot modify existing declarations with 
 UDAs.

  (attr) alias foo = bar; //  (attr) is ignored.
alias provides a way to provide an alternate name for a symbol.
I know what the intended semantics of alias is. But the reality is slightly different. See below.
 It wouldn't be an alternate name if it had different 
 attributes. Trying to make such work would have serious 
 semantic consequences.

 Hence, no, you cannot use alias to modify the attributes.
You can: public struct S { } private alias S S2; // visibility attribute is changed. Type modifiers: alias const(S) S2; // mutability attribute is changed. I am not saying that UDAs should be designed so that they could modify the aliased "symbols" (that would be a fatality) - just noting that alias is already NOT a plain alternative name.
Jan 04 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2013 2:03 PM, Max Samukha wrote:
 On Friday, 4 January 2013 at 20:40:39 UTC, Walter Bright wrote:
 Hence, no, you cannot use alias to modify the attributes.
You can: public struct S { } private alias S S2; // visibility attribute is changed.
I'm not really sure if this is an issue or not. I'll have to think about it. The visibility "attribute" is a bit of an oddity.
 Type modifiers:

 alias const(S) S2; // mutability attribute is changed.
This is not a bug. const(S) is a type constructor, not an attribute, and you are aliasing a type, not a symbol.
Jan 04 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2013 8:04 AM, Philippe Sigaud wrote:
 So, I'm testing how to transfer UDA from one symbol to another.
Remember, attributes are attached to the declaration. They are not transferred through initializers. This will do the transfer: import std.stdio; void main() { (3, "hello") int i = 10; (__traits(getAttributes, i)) double d2; writeln("[",__traits(getAttributes, d2), "]"); }
Jan 04 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/4/13 3:51 PM, Walter Bright wrote:
 On 1/4/2013 8:04 AM, Philippe Sigaud wrote:
 So, I'm testing how to transfer UDA from one symbol to another.
Remember, attributes are attached to the declaration. They are not transferred through initializers. This will do the transfer: import std.stdio; void main() { (3, "hello") int i = 10; (__traits(getAttributes, i)) double d2; writeln("[",__traits(getAttributes, d2), "]"); }
For transfer templates are better than attributes. Andrei
Jan 04 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/4/2013 12:59 PM, Andrei Alexandrescu wrote:
 For transfer templates are better than attributes.
Sure, but I wanted to illustrate what was happening. Templates tend to obscure things.
Jan 04 2013
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Jan 4, 2013 at 9:59 PM, Andrei Alexandrescu <
SeeWebsiteForEmail erdani.org> wrote:

 On 1/4/13 3:51 PM, Walter Bright wrote:


 So, I'm testing how to transfer UDA from one symbol to another.


 This will do the transfer:

 import std.stdio;
 void main()
 {
  (3, "hello") int i = 10;
  (__traits(getAttributes, i)) double d2;
 writeln("[",__traits(**getAttributes, d2), "]");
 }
Yes, I know. I just want to automate the process. I want a function or some piece of code that can propagate attributes. For example, say I receive a piece of unvalidated input. I test it and it's OK. I want to return it, with a new attribute (say, Validated() ),while keeping the input attributes. Since it seems a common need, I was looking for a way to abstract the process somewhat. For now, we would return a Validated(initialValue) struct. I just want to see how attributes can be used here. It seems that: (Validated, __traits(getAttributes, input)) InputType temp; return temp; do not work. If attribute manipulation cannot be isolated in easily reusable code, that would be sad. Andrei:
 For transfer templates are better than attributes.
Could you please give an example?
Jan 04 2013
prev sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 January 2013 at 15:45:21 UTC, Philippe Sigaud wrote:
 OK, now that 2.061 is out, we have User-Defined Attributes 
 (UDAs).

 Except, there is no doc on them, no explanation, nothing. For 
 people who did not follow the monstrous threads in November, 
 it's as if UDA do not exist.
 ...
 Here is the executive summary:

 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.
This is sorta like tuples; But from the brief summaries I cannot fully understand how or where they would be used. I understand some attributes can be made and added that some compilers may use ( noreturn as an example), but outside of the compiler I'd need an example of how to make use of them. Since there's no runtime component, then aside from carrying a tuple and some information forward at compile-time, what else can it do? How would you use it? Are there any special tuple formats that give information to automatically be included/compiled into the structs/classes without having to resort to mixins? Curiously enough it seems like clone would be a useful example. Let's assume we want to write clone, it's meaning that rather than writing a custom postblit to it's done automatically. struct S { string identifier; int value; string[] attributes; // clone this(this) {attributes = attributes.dup;} } Normally you'd write a this(this) as above, but if we used UDA's how could it be used/implemented?
Jan 04 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-04 21:33, Era Scarecrow wrote:

 This is sorta like tuples; But from the brief summaries I cannot fully
 understand how or where they would be used. I understand some attributes
 can be made and added that some compilers may use ( noreturn as an
 example), but outside of the compiler I'd need an example of how to make
 use of them.

 Since there's no runtime component, then aside from carrying a tuple and
 some information forward at compile-time, what else can it do? How would
 you use it? Are there any special tuple formats that give information to
 automatically be included/compiled into the structs/classes without
 having to resort to mixins?
It could be used for serialization, for example. Have a look at my serialization library, Orange. http://dl.dropbox.com/u/18386187/orange_docs/orange.serialization.Serializable.html Look at the "NonSerialized" template, that could now be replaced by a UDA. Like this: class Foo { int a; NonSerialized int b; // will not be (de)serialized } -- /Jacob Carlborg
Jan 04 2013
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 04 Jan 2013 21:33:03 +0100
schrieb "Era Scarecrow" <rtcvb32 yahoo.com>:

 On Friday, 4 January 2013 at 15:45:21 UTC, Philippe Sigaud wrote:
 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.
This is sorta like tuples; But from the brief summaries I cannot fully understand how or where they would be used. I understand some attributes can be made and added that some compilers may use ( noreturn as an example), but outside of the compiler I'd need an example of how to make use of them.
One example is std.benchmark. It currently detects if a function is a benchmark function by checking the name: void benchmark_stdio(); With UDAs we can do this: benchmark stdio(); or benchmark("Benchmarking stdio reads, using xKB buffer") benchStdio1(); There's still the issue of "How do I get all the declarations in a module (/ the applications)", but UDAs already help a lot.
Jan 05 2013
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Clojure uses its metadata (attached to values, though, not declaration) to
put documentation strings there.

That's quite doable with D:

 (doc("This function does.... "))
auto foo()
{ ... }

I'm also interested in tagging data:

 (Sorted!(withThisFun)) someRange ...
 (Ranged(0.0, 1.0)) someRange ...

or:

 Validated SQLQuery query;
Jan 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-05 15:13, Philippe Sigaud wrote:
 Clojure uses its metadata (attached to values, though, not declaration)
 to put documentation strings there.

 That's quite doable with D:

  (doc("This function does.... "))
 auto foo()
 { ... }

 I'm also interested in tagging data:

  (Sorted!(withThisFun)) someRange ...
  (Ranged(0.0, 1.0)) someRange ...
Just for the record, the extra parentheses are not needed: doc("This function does.... ") auto foo () { } Sorted!(withThisFun) someRange ... -- /Jacob Carlborg
Jan 05 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 5, 2013 at 6:00 PM, Jacob Carlborg <doob me.com> wrote:

 Just for the record, the extra parentheses are not needed:

  doc("This function does.... ") auto foo () {  }
  Sorted!(withThisFun) someRange ...
Good to know. I tested it with basic values and this fails: "hello" int i; 3 inj j; Worth a bug report? As a complement, multiple 's are possible: ("hello") (3) int j; And another complement: struct S {} S S s; is possible. But int S s; is not So user-defined types are OK, but not basic types. Looks like a parsing/grammar problem for me, since attribute tuple sure should be able to store built-in types. Another bug report?
Jan 05 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-05 19:54, Philippe Sigaud wrote:

 Good to know. I tested it with basic values and this fails:

  "hello" int i;
  3 inj j;

 Worth a bug report?
No, that's by design. When I added that syntax first but I was asked to change it to only accept call expressions. Have a look at the grammar: https://dl.dropbox.com/u/18386187/attribute.html#uda
 As a complement, multiple  's are possible:

  ("hello")  (3) int j;
Yes, that's legal and is supposed to be. Have a look at Walters original announcement: http://forum.dlang.org/thread/k7afq6$2832$1 digitalmars.com enum EEE = 7; ["hello"] struct SSS { } [3] { [4][EEE][SSS] int foo; } With the correct syntax that becomes: enum EEE = 7; ("hello") struct SSS { } (3) { (4) (EEE) (SSS) int foo; } Or: (3) { (4) EEE SSS int foo; }
 And another complement:

 struct S {}

  S S s; is possible.
 But

  int S s;

 is not
That is not supposed to be legal (see above), but this might be: (int) S s; Does that work?
 So user-defined types are OK, but not basic types. Looks like a
 parsing/grammar problem for me, since attribute tuple sure should be
 able to store built-in types.
 Another bug report?
I'm not sure. -- /Jacob Carlborg
Jan 05 2013
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 No, that's by design. When I added that syntax first but I was asked to
 change it to only accept call expressions.
  int S s;

 is not
That is not supposed to be legal (see above), but this might be: (int) S s; Does that work?
No. It produces reams of error.
  So user-defined types are OK, but not basic types. Looks like a
 parsing/grammar problem for me, since attribute tuple sure should be
 able to store built-in types.
 Another bug report?
I'm not sure.
I find it strange that MyType ... is OK, but not 3, when, at the same time (MyType) and (3) are *both* OK. Also, why is ("hello") and (SomeType) authorized, but not (int)? One extreme or the other looks OK for me: either only user-defined types are authorized (no int, no 3) or everything a tuple can hold is authorized (hence, int). The latter is more in line with the D way. Also, if parenthesis can be dropped, allow them to be dropped for anything that's a token long, as is done for template arguments. That seems coherent with the rest of the language.
Jan 05 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2013 10:54 AM, Philippe Sigaud wrote:
 Another bug report?
This is as designed, not a bug. The attribute must start with a ( or identifier. Not keyword, number, string, operator, etc. If you want, file an enhancement request for more. But the design was deliberately restrictive for now.
Jan 05 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 5, 2013 at 10:20 PM, Walter Bright
<newshound2 digitalmars.com>wrote:

 On 1/5/2013 10:54 AM, Philippe Sigaud wrote:

 Another bug report?
This is as designed, not a bug. The attribute must start with a ( or identifier. Not keyword, number, string, operator, etc.
That, I can understand. But why is (MyType) accepted, whereas (int) is not?
Jan 05 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
Jan 05 2013
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 5, 2013 at 11:14 PM, Walter Bright
<newshound2 digitalmars.com>wrote:

 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:

 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
Well, first that would be nice to have the grammar online :) Even if I understand the grammar restriction, from a user PoV this is quite unexpected: a built-in type is a completely legal part of a D tuple. Either it should be restricted to user-defined types (something I don't like), or, if attributes are supposed to be tuples, then any tuple element should be authorized. And I will not buy a possible argument saying that I can wrap an int inside a user-defined type. Yes, I can. But then, there is the same solution for (3) or ("Hello") and *these* are legal.
Jan 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-05 23:44, Philippe Sigaud wrote:

 Well, first that would be nice to have the grammar online :)
Yeah, still waiting for that pull request to be merged. -- /Jacob Carlborg
Jan 05 2013
parent reply "Domain" <dont_email empty.com> writes:
On Saturday, 5 January 2013 at 22:57:03 UTC, Jacob Carlborg wrote:
 On 2013-01-05 23:44, Philippe Sigaud wrote:

 Well, first that would be nice to have the grammar online :)
Yeah, still waiting for that pull request to be merged.
UDA can not apply to function argument? enum attr; void func( attr int a) // <-- error { attr int b; // <-- ok }
Jan 05 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2013 10:57 PM, Domain wrote:
 On Saturday, 5 January 2013 at 22:57:03 UTC, Jacob Carlborg wrote:
 On 2013-01-05 23:44, Philippe Sigaud wrote:

 Well, first that would be nice to have the grammar online :)
Yeah, still waiting for that pull request to be merged.
UDA can not apply to function argument? enum attr; void func( attr int a) // <-- error { attr int b; // <-- ok }
Currently, no.
Jan 05 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Jan 6, 2013 at 8:16 AM, Walter Bright <newshound2 digitalmars.com>wrote:
 UDA can not apply to function argument?
Currently, no.
Walter, what is the official way to return an attributed value? XXX? foo() { Marked int i; return i; }
Jan 06 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 1:48 AM, Philippe Sigaud wrote:
 Walter, what is the official way to return an attributed value?

 XXX? foo()
 {
       Marked int i;
      return i;
 }
Values do not have attributes. Attributes are attached to symbols - not values or types.
Jan 06 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-06 10:48, Philippe Sigaud wrote:

 Walter, what is the official way to return an attributed value?

 XXX? foo()
 {
       Marked int i;
      return i;
 }
Don't know if this is what you want but: struct Marked {} struct Attrs (T...) {} auto bar () { Marked int i; return Attrs!(__traits(getAttributes, i))(); } void main () { writeln(bar()); // prints Attrs!(Marked)() } -- /Jacob Carlborg
Jan 06 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
 Don't know if this is what you want but:

 struct Marked {}
 struct Attrs (T...) {}

 auto bar ()
 {
      Marked int i;
     return Attrs!(__traits(getAttributes, i))();
 }

 void main ()
 {
     writeln(bar()); // prints Attrs!(Marked)()
 }
I just want to be able to return an attributed something. How can a function return something that's attributed? IIUC what Walter said, a function cannot return an attributed value: any internal symbol can be attributed, but these cannot get out. I can create can attributed value to 'catch' what a function returns, but not automatically: ??? attributedInt() { ("Hello") int i = 1; return i; } void main() { ??? j = attributedInt(); // How to have j get the ("Hello") attribute? } The only way would be what you suggest: - extract the attributes from the internal i - store them in a specially-crafted struct - return that - in the external code, catch the returned struct - extract the artificially stored attributes - generate a new value with the same attributes. Ugh.
Jan 06 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-06 14:29, Philippe Sigaud wrote:

 I just want to be able to return an attributed something. How can a
 function return something that's attributed?

 IIUC what Walter said, a function cannot return an attributed value: any
 internal symbol can be attributed, but these cannot get out.
 I can create can attributed value to 'catch' what a function returns,
 but not automatically:

 ??? attributedInt()
 {
       ("Hello") int i = 1;
      return i;
 }

 void main()
 {
      ??? j = attributedInt();
      // How to have j get the  ("Hello") attribute?
 }

 The only way would be what you suggest:

 - extract the attributes from the internal i
 - store them in a specially-crafted struct
 - return that
 - in the external code, catch the returned struct
 - extract the artificially stored attributes
 - generate a new value with the same attributes.
Basically, yes. I haven't been able figured out something else. -- /Jacob Carlborg
Jan 06 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-06 14:29, Philippe Sigaud wrote:
     Don't know if this is what you want but:

     struct Marked {}
     struct Attrs (T...) {}

     auto bar ()
     {
           Marked int i;
          return Attrs!(__traits(getAttributes, i))();
     }

     void main ()
     {
          writeln(bar()); // prints Attrs!(Marked)()
     }


 I just want to be able to return an attributed something. How can a
 function return something that's attributed?

 IIUC what Walter said, a function cannot return an attributed value: any
 internal symbol can be attributed, but these cannot get out.
 I can create can attributed value to 'catch' what a function returns,
 but not automatically:

 ??? attributedInt()
 {
       ("Hello") int i = 1;
      return i;
 }

 void main()
 {
      ??? j = attributedInt();
      // How to have j get the  ("Hello") attribute?
 }

 The only way would be what you suggest:

 - extract the attributes from the internal i
 - store them in a specially-crafted struct
 - return that
 - in the external code, catch the returned struct
 - extract the artificially stored attributes
 - generate a new value with the same attributes.
You can perhaps encapsulate this in a mixin? -- /Jacob Carlborg
Jan 06 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
The only way would be what you suggest:
 - extract the attributes from the internal i
 - store them in a specially-crafted struct
 - return that
 - in the external code, catch the returned struct
 - extract the artificially stored attributes
 - generate a new value with the same attributes.
You can perhaps encapsulate this in a mixin?
That would mean two mixins, one internal and one external. Plus, that means every function where I want to propagate UDA has to be crafted exactly for this need. This is a drag. It seems natural to me that int foo(int i) { return i;} should forward i attributes. But maybe I need a shift my way to think about attributes. They are attached to declarations, not values... That's too bad, because declaring UDA is simple, and receiving them with arguments is easy also. There is a fundamental imbalance in having having propagating attributes through functions so difficult.
Jan 06 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-06 15:25, Philippe Sigaud wrote:

 That would mean two mixins, one internal and one external. Plus, that
 means every function where I want to propagate UDA has to be crafted
 exactly for this need.

 This is a drag. It seems natural to me that

 int foo(int i) { return i;}

 should forward i attributes. But maybe I need a shift my way to think
 about attributes. They are attached to declarations, not values...
Exactly.
 That's too bad, because declaring UDA is simple, and receiving them with
 arguments is easy also. There is a fundamental imbalance in having
 having propagating attributes through functions so difficult.
Yeah, if you want to work with UDA's you need to work with symbols, not values or types. If you want to pass a symbol, including its UDA, you need to pass it as an alias: void foo (alias symbol) () { // access UDA of symbol } (3) int a; foo!(a); -- /Jacob Carlborg
Jan 06 2013
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Jan 6, 2013 at 3:29 PM, Jacob Carlborg <doob me.com> wrote:

 Yeah, if you want to work with UDA's you need to work with symbols, not
 values or types. If you want to pass a symbol, including its UDA, you need
 to pass it as an alias:
That was the explanation I needed: UDA are attached to symbols. Now that's, clearer ;) Hmm, did anyone try to put attribute before a function overload and not another? Ca (PS: symbols, except modules, because they are second-class citizens)
Jan 06 2013
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Hmm, did anyone try to put attribute before a function overload and not
 another?
 Ca
Damn tab. Can attributes be defined by templates arguments? (T) class C(T) : T { } Answer: no. OK.
Jan 06 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/06/2013 07:24 PM, Philippe Sigaud wrote:
 Can attributes be defined by templates arguments?


  (T) class C(T) : T { }

 Answer: no. OK.
This works: template C(T){ T class C : T { } } The above appears to annotate the template itself, which is inconsistent. You should probably file a bug report.
Jan 06 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/6/13 9:25 AM, Philippe Sigaud wrote:
 That's too bad, because declaring UDA is simple, and receiving them with
 arguments is easy also. There is a fundamental imbalance in having
 having propagating attributes through functions so difficult.
<brokenrecord>For designing attributes that navigate with types templates would be the solution of choice.</brokenrecord> Andrei
Jan 06 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 <brokenrecord>For designing attributes that navigate with types 
 templates would be the solution of choice.</brokenrecord>
There's an interesting cognitive impercetion phenomena here, that's worth studying and not ignoring. From the little evidence here, it seems that D programmers want to use UDAs instead of templates for those purposes. Possibly because UDAs look more fit (despite you rightfully say they aren't). Bye, bearophile
Jan 06 2013
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Jan 6, 2013 at 3:58 PM, Andrei Alexandrescu <
SeeWebsiteForEmail erdani.org> wrote:

 On 1/6/13 9:25 AM, Philippe Sigaud wrote:

 That's too bad, because declaring UDA is simple, and receiving them with
 arguments is easy also. There is a fundamental imbalance in having
 having propagating attributes through functions so difficult.
<brokenrecord>For designing attributes that navigate with types templates would be the solution of choice.</brokenrecord>
Care to show a small example? I tried 1-2 years ago. With alias this, that's partially acceptable. I just remember it was a bit burdensome tp use and dumped it. But OK, if UDA do not do that, then I'll go back to templates. Since alias this become better, maybe something can be done here.
Jan 06 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 6 January 2013 at 14:58:07 UTC, Andrei Alexandrescu 
wrote:
 On 1/6/13 9:25 AM, Philippe Sigaud wrote:
 That's too bad, because declaring UDA is simple, and receiving 
 them with
 arguments is easy also. There is a fundamental imbalance in 
 having
 having propagating attributes through functions so difficult.
<brokenrecord>For designing attributes that navigate with types templates would be the solution of choice.</brokenrecord> Andrei
Isn't it better to achieve this with a template ?
Jan 06 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/06/2013 11:27 PM, deadalnix wrote:
 On Sunday, 6 January 2013 at 14:58:07 UTC, Andrei Alexandrescu wrote:
 On 1/6/13 9:25 AM, Philippe Sigaud wrote:
 That's too bad, because declaring UDA is simple, and receiving them with
 arguments is easy also. There is a fundamental imbalance in having
 having propagating attributes through functions so difficult.
<brokenrecord>For designing attributes that navigate with types templates would be the solution of choice.</brokenrecord> Andrei
Isn't it better to achieve this with a template ?
No, it is equivalent.
Jan 06 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Jan 06 2013
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Jan 6, 2013 at 11:24 PM, deadalnix <deadalnix gmail.com> wrote:

 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:

 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:

 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Same thought here.
Jan 06 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/06/2013 11:24 PM, deadalnix wrote:
 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Sure! ... struct IdentifierExp : Expression { Identifier *ident; Declaration *var; ...
Jan 06 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 2:24 PM, deadalnix wrote:
 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Parsing happens before semantic analysis. Hence, MyType looks like an expression.
Jan 06 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 7 January 2013 at 00:38:35 UTC, Walter Bright wrote:
 On 1/6/2013 2:24 PM, deadalnix wrote:
 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright 
 wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Parsing happens before semantic analysis. Hence, MyType looks like an expression.
OK, but if int is invalid, should semantic analysis reject MyType as well ?
Jan 06 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 5:06 PM, deadalnix wrote:
 On Monday, 7 January 2013 at 00:38:35 UTC, Walter Bright wrote:
 On 1/6/2013 2:24 PM, deadalnix wrote:
 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Parsing happens before semantic analysis. Hence, MyType looks like an expression.
OK, but if int is invalid, should semantic analysis reject MyType as well ?
Tuples accept both types and expressions, and the semantic analyzer loads it into the tuple.
Jan 06 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/07/2013 01:38 AM, Walter Bright wrote:
 On 1/6/2013 2:24 PM, deadalnix wrote:
 On Saturday, 5 January 2013 at 22:14:47 UTC, Walter Bright wrote:
 On 1/5/2013 2:06 PM, Philippe Sigaud wrote:
 But why is  (MyType) accepted, whereas  (int) is not?
Because it's looking for an expression inside the parents, and int is not an expression.
And mytype is an expression ?????
Parsing happens before semantic analysis. Hence, MyType looks like an expression.
Sure, that is how the compiler currently works. The compiler is an inadequate reference at this point. (Eg. I am still reducing the massive breakage introduced by 2.061 regressions. Mostly 'forward reference' errors -- mentioned nowhere in the spec, and seemingly introduced in order to 'fix' ICEs.) Why does it make sense from the standpoint of language design? The compiler should obviously use the part of the parser that parses template arguments to parse UDA's. I am surprised this is not what is done. Also, this particular problem would not exist in the first place if basic types just were treated like expressions in the parser. I am not familiar with DMD, but I bet the special casing of built-ins leaves an ugly trail in the code base.
Jan 06 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/07/2013 04:27 AM, Timon Gehr wrote:
 ... (Eg. I am still reducing the massive breakage introduced by 2.061
 regressions. Mostly 'forward reference' errors -- mentioned nowhere in
 the spec, and seemingly introduced in order to 'fix' ICEs.) ...
dustmite ftw. http://d.puremagic.com/issues/show_bug.cgi?id=9276
Jan 06 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 8:37 PM, Timon Gehr wrote:
 dustmite ftw.

 http://d.puremagic.com/issues/show_bug.cgi?id=9276
Thank you.
Jan 06 2013
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Mon, Jan 7, 2013 at 4:27 AM, Timon Gehr <timon.gehr gmx.ch> wrote:

 The compiler should obviously use the part of the parser that parses
 template arguments to parse UDA's. I am surprised this is not what is done.
I humbly concur. Walter, you yourself presented UDAs as 'linking the dots' between different part of the D language (tuples...). It's an interesting and elegant approach, but the current situation is somewhat inadequate: UDA can be manipulated like template tuple parameters and should be parsed as such.
Jan 06 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 9:44 PM, Philippe Sigaud wrote:
 I humbly concur. Walter, you yourself presented UDAs as 'linking the dots'
 between different part of the D language (tuples...). It's an interesting and
 elegant approach, but the current situation is somewhat inadequate: UDA can be
 manipulated like template tuple parameters and should be parsed as such.
Well, I am glad to see people using it.
Jan 06 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 7:27 PM, Timon Gehr wrote:
 I am still reducing the massive breakage
 introduced by 2.061 regressions.
Sorry about that, but 2.061 has been available for 2 months in beta. We fixed all but 3 of the reported regressions, and had good reasons for deferring those. In fact, the 2.062 work in progress release is currently up on the site.
Jan 06 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/07/2013 07:27 AM, Walter Bright wrote:
 On 1/6/2013 7:27 PM, Timon Gehr wrote:
 I am still reducing the massive breakage
 introduced by 2.061 regressions.
Sorry about that,
No problem. There will be some way to get it to compile. The reduced code shows which points to concentrate modification on. I have quite a few workarounds for forward reference errors in my code already.
 but 2.061 has been available for 2 months in beta.
I think this is a valid point, but coincidentally, I have not been working on the code base for the past 2 months.
 We fixed all but 3 of the reported regressions, and had good reasons for
 deferring those.
I am sure that very good progress is being made. However, the forward reference error problem will need formal treatment at some point. I think one reason they pop up is that symbol lookup for the intended language is inherently impossible to compute.
 In fact, the 2.062 work in progress release is currently up on the site.
Great! The remark was not intended as a critique of DMD's development process, rather I was attempting to support the point that for language design issues, implementation details are of secondary importance.
Jan 06 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/6/2013 11:31 PM, Timon Gehr wrote:
 I am sure that very good progress is being made. However, the forward reference
 error problem will need formal treatment at some point. I think one reason they
 pop up is that symbol lookup for the intended language is inherently impossible
 to compute.
A huge source of fwd ref problems was not at all about symbol lookup. It was about partial types referencing properties of themselves. For example, struct S { int a; int b = S.sizeof; int c; } for a simple example. There've been all kinds of variations on this theme, some of them wickedly complicated, but always boiling down to the same general issue. Some forward ref regressions have cropped up because the compiler now does a better job of checking if there is enough of the type computed to get the desired property. Formerly, it would just return an incorrect size (for example). (I do not know if this is the case for your example, yet.)
Jan 06 2013
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 7 January 2013 at 07:58:29 UTC, Walter Bright wrote:
 A huge source of fwd ref problems was not at all about symbol 
 lookup. It was about partial types referencing properties of 
 themselves. For example,

 struct S {
     int a;
     int b = S.sizeof;
     int c;
 }

 for a simple example. There've been all kinds of variations on 
 this theme, some of them wickedly complicated, but always 
 boiling down to the same general issue.

 Some forward ref regressions have cropped up because the 
 compiler now does a better job of checking if there is enough 
 of the type computed to get the desired property. Formerly, it 
 would just return an incorrect size (for example). (I do not 
 know if this is the case for your example, yet.)
I've had certain headaches from that as well trying to make my polymorphic struct, it's easy to see how it can get lost. struct S { static struct Data { int i; } union { Data data; S2 s2; //problem line } } struct S2 { S base; //problem line } Here the whole size is defined by Data, however because S2 references S1 before it has a concrete size it can get stuck (may still get stuck, not sure). Hmmm in cases like this, a size attribute could be useful (forces it to believe given size rather than looking it up). So that could become: union { Data data; size(Data.sizeof) S2 s2; //size hint, forward ref problem gone }
Jan 07 2013
prev sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 5 January 2013 at 11:57:39 UTC, Johannes Pfau wrote:
 Era Scarecrow wrote:
 This is sorta like tuples; But from the brief summaries I 
 cannot fully understand how or where they would be used. I 
 understand some attributes can be made and added that some 
 compilers may use ( noreturn as an example), but outside of 
 the compiler I'd need an example of how to make use of them.
One example is std.benchmark. It currently detects if a function is a benchmark function by checking the name: void benchmark_stdio(); With UDAs we can do this: benchmark stdio(); or benchmark("Benchmarking stdio reads, using xKB buffer") benchStdio1(); There's still the issue of "How do I get all the declarations in a module (/ the applications)", but UDAs already help a lot.
Yes I understand how you can attach some information using a UDA, but that still doesn't tell me _how to use_ it. Unless you can somehow locate & manipulate/use/pass the information around than it's no more than a comment that isn't removed immediately. Slightly off topic: I get the feeling that with the questions of current specs, the large number of changes (few hugely breaking) and outdated TDPL the language documentation needs a good through update. Perhaps a TDPL v2 regarding changes to the language; Rather than replacing TDPL, it instead it compliments it. And when phobos is more mature and isn't going to be changing then an API/reference book for it would likely be a third book.
Jan 06 2013