Skip to content

Commit d297204

Browse files
authored
[spec/attribute] Improve UDA docs (dlang#3598)
* [spec/attribute] Improve docs Add missing @Identifier grammar. Fix: UDAs are not just expressions, they can be @sometype. Describe kinds of UDA. Add comments & show @constant in first example. Describe type instance UDA. Show function parameter with UDA. Add subheading for getAttributes. Use sequence not expression tuple, link to sequence docs, tweak wording. (They can include types not just expressions). Add newlines for getAttributes example, use lowercase for manifest constant. Add usage subheading, remove redundant sentence about tuples. * @Identifier is covered by TemplateSingleArgument * whitespace
1 parent fd1f289 commit d297204

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

spec/attribute.dd

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,29 +1020,40 @@ $(GNAME UserDefinedAttribute):
10201020
)
10211021

10221022
$(P
1023-
User-Defined Attributes (UDA) are compile-time expressions that can be attached
1023+
User-Defined Attributes (UDA) are compile-time annotations that can be attached
10241024
to a declaration. These attributes can then be queried, extracted, and manipulated
10251025
at compile time. There is no runtime component to them.
10261026
)
10271027

1028-
A user-defined attribute looks like:
1028+
A user-defined attribute is defined using:
1029+
* Compile-time expressions
1030+
* A named manifest constant
1031+
* A type name
1032+
* A type to instantiate using a compile-time argument list
10291033

1034+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
10301035
---
1031-
@(3) int a;
1032-
---
1033-
---
1034-
@("string", 7) int b;
1036+
@(3) int a; // value argument
1037+
@("string", 7) int b; // multiple values
1038+
1039+
// using compile-time constant
1040+
enum val = 3;
1041+
@val int a2; // has same attribute as `a`
10351042

10361043
enum Foo;
1037-
@Foo int c;
1044+
@Foo int c; // type name attribute
10381045

10391046
struct Bar
10401047
{
10411048
int x;
10421049
}
1043-
1044-
@Bar(3) int d;
1050+
@Bar() int d; // type instance
1051+
@Bar(3) int e; // type instance using initializer
10451052
---
1053+
)
1054+
$(P For `e`, the attribute is an instance of struct `Bar` which is
1055+
$(DDSUBLINK spec/struct, static_struct_init, statically initialized)
1056+
using its argument.)
10461057

10471058
$(P
10481059
If there are multiple UDAs in scope for a declaration, they are concatenated:
@@ -1056,8 +1067,16 @@ struct Bar
10561067
}
10571068
---
10581069

1070+
$(P A function parameter can have a UDA:)
1071+
---
1072+
void f(@(3) int p);
1073+
---
1074+
1075+
$(H3 $(LNAME2 getAttributes, `__traits(getAttributes)`))
1076+
10591077
$(P
1060-
UDAs can be extracted into an expression tuple using $(D __traits):
1078+
UDAs can be extracted into a
1079+
$(DDSUBLINK spec/template, variadic-templates, compile-time sequence) using $(D __traits):
10611080
)
10621081

10631082
---
@@ -1066,15 +1085,19 @@ pragma(msg, __traits(getAttributes, s)); // prints tuple('c')
10661085
---
10671086

10681087
$(P
1069-
If there are no user-defined attributes for the symbol, an empty tuple is returned.
1070-
The expression tuple can be turned into a manipulatable tuple:
1088+
If there are no user-defined attributes for the symbol, an empty sequence is returned.
1089+
The result can be used just like any compile-time sequence - it can be indexed,
1090+
passed as template parameters, etc.
10711091
)
10721092

10731093
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
10741094
---
1075-
enum EEE = 7;
1095+
enum e = 7;
10761096
@("hello") struct SSS { }
1077-
@(3) { @(4) @EEE @SSS int foo; }
1097+
@(3)
1098+
{
1099+
@(4) @e @SSS int foo;
1100+
}
10781101

10791102
alias TP = __traits(getAttributes, foo);
10801103

@@ -1084,7 +1107,7 @@ pragma(msg, TP[2]); // prints 7
10841107
)
10851108

10861109
$(P
1087-
Of course the tuple types can be used to declare things:
1110+
Any types in the sequence can be used to declare things:
10881111
)
10891112

10901113
---
@@ -1096,14 +1119,15 @@ TP[3] a; // a is declared as an SSS
10961119
)
10971120

10981121
---
1122+
pragma(msg, __traits(getAttributes, a)); // prints tuple()
10991123
pragma(msg, __traits(getAttributes, typeof(a))); // prints tuple("hello")
11001124
---
11011125

1126+
$(H3 $(LNAME2 uda-usage, Usage))
1127+
11021128
$(P
11031129
Of course, the real value of UDAs is to be able to create user-defined types with
11041130
specific values. Having attribute values of basic types does not scale.
1105-
The attribute tuples can be manipulated like any other tuple, and can be passed as
1106-
the argument list to a template.
11071131
)
11081132

11091133
$(P

0 commit comments

Comments
 (0)