$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Attributes, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_ITEM linkage, Linkage Attribute) $(HEADERNAV_SUBITEMS align, $(D align) Attribute, $(HEADERNAV_ITEM align_gc, GC Compatibility) ) $(HEADERNAV_ITEM deprecated, $(D deprecated) Attribute) $(HEADERNAV_SUBITEMS visibility_attributes, Visibility Attribute, $(HEADERNAV_ITEM export, $(D export) Attribute) $(HEADERNAV_ITEM package, $(D package) Attribute) $(HEADERNAV_ITEM private, $(D private) Attribute) $(HEADERNAV_ITEM protected, $(D protected) Attribute) $(HEADERNAV_ITEM public, $(D public) Attribute) ) $(HEADERNAV_SUBITEMS mutability, Mutability Attributes, $(HEADERNAV_ITEM const, $(D const) Attribute) $(HEADERNAV_ITEM immutable, $(D immutable) Attribute) $(HEADERNAV_ITEM inout, $(D inout) Attribute) ) $(HEADERNAV_SUBITEMS shared-storage, Shared Storage Attributes, $(HEADERNAV_ITEM shared, $(D shared) Attribute) $(HEADERNAV_ITEM gshared, $(D __gshared) Attribute) $(HEADERNAV_ITEM synchronized, $(D @synchronized) Attribute) ) $(HEADERNAV_ITEM disable, $(D @disable) Attribute) $(HEADERNAV_ITEM safe, $(D @safe), $(D @trusted), and $(D @system) Attribute) $(HEADERNAV_SUBITEMS function-attributes, Function Attributes, $(HEADERNAV_ITEM nogc, $(D @nogc) Attribute) $(HEADERNAV_ITEM property, $(D @property) Attribute) $(HEADERNAV_ITEM nothrow, $(D nothrow) Attribute) $(HEADERNAV_ITEM pure, $(D pure) Attribute) $(HEADERNAV_ITEM ref, $(D ref) Attribute) $(HEADERNAV_ITEM return, $(D return) Attribute) ) $(HEADERNAV_ITEM static, $(D static) Attribute) $(HEADERNAV_ITEM auto, $(D auto) Attribute) $(HEADERNAV_SUBITEMS scope, $(D scope) Attribute, $(HEADERNAV_ITEM scope-values, Scope Values) $(HEADERNAV_ITEM scope-class-var, $(D scope) Class Instances) ) $(HEADERNAV_SUBITEMS class-attributes, OOP Attributes, $(HEADERNAV_ITEM abstract, $(D abstract) Attribute) $(HEADERNAV_ITEM final, final Attribute) $(HEADERNAV_ITEM override, $(D override) Attribute) ) $(HEADERNAV_ITEM mustuse-attribute, @mustuse Attribute) $(HEADERNAV_SUBITEMS uda, User-Defined Attributes, $(HEADERNAV_ITEM getAttributes, __traits(getAttributes)) $(HEADERNAV_ITEM uda-usage, Usage) $(HEADERNAV_ITEM uda-templates, Templates) ) ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AttributeSpecifier): $(GLINK Attribute) $(D :) $(GLINK Attribute) $(GLINK DeclarationBlock) $(DDOC_BLANKLINE ) $(GNAME Attribute): $(GLINK AlignAttribute) $(GLINK AtAttribute) $(GLINK DeprecatedAttribute) $(GLINK FunctionAttributeKwd) $(GLINK LinkageAttribute) $(GLINK2 pragma, Pragma) $(GLINK VisibilityAttribute) $(RELATIVE_LINK2 abstract, $(D abstract)) $(RELATIVE_LINK2 auto, $(D auto)) $(RELATIVE_LINK2 const, $(D const)) $(RELATIVE_LINK2 final, final) $(RELATIVE_LINK2 gshared, $(D __gshared)) $(RELATIVE_LINK2 linkage, $(D extern)) $(RELATIVE_LINK2 immutable, $(D immutable)) $(RELATIVE_LINK2 inout, $(D inout)) $(RELATIVE_LINK2 override, $(D override)) $(RELATIVE_LINK2 ref, $(D ref)) $(RELATIVE_LINK2 return, $(D return)) $(RELATIVE_LINK2 scope, $(D scope)) $(RELATIVE_LINK2 shared, $(D shared)) $(RELATIVE_LINK2 static, $(D static)) $(RELATIVE_LINK2 synchronized, synchronized) $(DDOC_BLANKLINE ) $(GNAME FunctionAttributeKwd): $(RELATIVE_LINK2 nothrow, $(D nothrow)) $(RELATIVE_LINK2 pure, $(D pure)) $(DDOC_BLANKLINE ) $(GNAME AtAttribute): $(D @) $(RELATIVE_LINK2 disable, $(D disable)) $(D @) $(RELATIVE_LINK2 nogc, $(D nogc)) $(D @) $(DDLINK spec/ob, Live Functions, live) $(GLINK Property) $(D @) $(RELATIVE_LINK2 safe, $(D safe)) $(D @) $(RELATIVE_LINK2 safe, $(D system)) $(D @) $(RELATIVE_LINK2 safe, $(D trusted)) $(GLINK UserDefinedAttribute) $(DDOC_BLANKLINE ) $(GNAME Property): $(D @) $(RELATIVE_LINK2 property, $(D property)) $(DDOC_BLANKLINE ) $(GNAME DeclarationBlock): $(GLINK2 module, DeclDef) $(D {) $(GLINK2 module, DeclDefs)$(OPT ) $(D }) ) $(DDOC_BLANKLINE ) $(P Attributes are a way to modify one or more declarations. The general forms are: ) $(DDOC_BLANKLINE ) $(D_CODE attribute declaration; $(D_COMMENT // affects the declaration ) attribute: $(D_COMMENT // affects all declarations until the end of ) $(D_COMMENT // the current scope ) declaration; declaration; ... attribute { $(D_COMMENT // affects all declarations in the block ) declaration; declaration; ... } ) $(DDOC_BLANKLINE )

$(LNAME2 linkage, Linkage Attribute)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME LinkageAttribute): $(D extern) $(D $(LPAREN)) $(GLINK LinkageType) $(D $(RPAREN )) $(D extern) $(D $(LPAREN)) $(D C) $(D ++) $(D ,) $(D $(RPAREN )) $(D extern) $(D $(LPAREN)) $(D C) $(D ++) $(D ,) $(GLINK2 type, QualifiedIdentifier) $(D $(RPAREN )) $(D extern) $(D $(LPAREN)) $(D C) $(D ++) $(D ,) $(GLINK NamespaceList) $(D $(RPAREN )) $(D extern) $(D $(LPAREN)) $(D C) $(D ++) $(D ,) $(D class) $(D $(RPAREN )) $(D extern) $(D $(LPAREN)) $(D C) $(D ++) $(D ,) $(D struct) $(D $(RPAREN )) $(DDOC_BLANKLINE ) $(GNAME LinkageType): $(D C) $(D C) $(D ++) $(D D) $(D Windows) $(D System) $(D Objective) $(D -) $(D C) $(DDOC_BLANKLINE ) $(GNAME NamespaceList): $(GLINK2 expression, ConditionalExpression) $(GLINK2 expression, ConditionalExpression)$(D ,) $(GLINK2 expression, ConditionalExpression)$(D ,) $(GSELF NamespaceList) ) $(DDOC_BLANKLINE ) $(P D provides an easy way to call C functions and operating system API functions, as compatibility with both is essential. The $(I LinkageType) is case sensitive, and is meant to be extensible by the implementation ($(I they are not keywords)). $(D C) and $(D D) must be supplied, the others are what makes sense for the implementation. $(D C++) offers limited compatibility with C++, see the $(LINK2 cpp_interface.html, Interfacing to C++) documentation for more information. $(D Objective-C) offers compatibility with Objective-C, see the $(LINK2 objc_interface.html, Interfacing to Objective-C) documentation for more information. $(D System) is the same as $(D Windows) on Windows platforms, and $(D C) on other platforms. ) $(P $(B Implementation Note:) for Win32 platforms, $(D Windows) should exist. ) $(DDOC_BLANKLINE ) $(P C function calling conventions are specified by: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (C): $(D_KEYWORD int) foo(); $(D_COMMENT // call foo$(LPAREN)$(RPAREN ) with C conventions )) Note that extern(C) can be provided for all types of declarations, including struct or class, even though there is no corresponding match on the C side. In that case, the attribute is ignored. This behavior applies for nested functions and nested variables as well. However, for static member methods and static nested functions, adding extern(C) will change the calling convention, but not the mangling. $(DDOC_BLANKLINE ) $(P D conventions are:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (D): ) $(DDOC_BLANKLINE ) $(P Windows API conventions are:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (Windows): $(D_KEYWORD void) *VirtualAlloc( $(D_KEYWORD void) *lpAddress, $(D_KEYWORD uint) dwSize, $(D_KEYWORD uint) flAllocationType, $(D_KEYWORD uint) flProtect ); ) $(DDOC_BLANKLINE ) $(P The Windows convention is distinct from the C convention only on Win32 platforms, where it is equivalent to the $(LINK2 https://en.wikipedia.org/wiki/X86_calling_conventions, stdcall) convention.) $(DDOC_BLANKLINE ) $(P Note that a $(DDSUBLINK spec/declaration, extern, lone $(D extern) keyword) is used as a storage class.) $(DDOC_BLANKLINE )

C++ $(LNAME2 namespace, Namespaces)

$(DDOC_BLANKLINE ) $(P The linkage form $(D extern $(LPAREN)C++, )$(I QualifiedIdentifier)$(D $(RPAREN )) creates C++ declarations that reside in C++ namespaces. The $(I QualifiedIdentifier) specifies the namespaces. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (C++, N) { $(D_KEYWORD void) foo(); } ) $(DDOC_BLANKLINE ) $(P refers to the C++ declaration:) $(DDOC_BLANKLINE ) $(CPPCODE namespace N { void foo(); }) $(DDOC_BLANKLINE ) $(P and can be referred to with or without qualification:) $(DDOC_BLANKLINE ) $(D_CODE foo(); N.foo(); ) $(DDOC_BLANKLINE ) $(P Namespaces create a new named scope that is imported into its enclosing scope.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD extern) (C++, N) { $(D_KEYWORD void) foo(); $(D_KEYWORD void) bar(); } $(D_KEYWORD extern) (C++, M) { $(D_KEYWORD void) foo(); } $(D_KEYWORD void) main() { bar(); $(D_COMMENT // ok ) $(D_COMMENT //foo$(LPAREN)$(RPAREN ); // error - N.foo$(LPAREN)$(RPAREN ) or M.foo$(LPAREN)$(RPAREN ) ? ) M.foo(); $(D_COMMENT // ok )} ) ) $(DDOC_BLANKLINE ) $(P Multiple dotted identifiers in the $(I QualifiedIdentifier) create nested namespaces:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (C++, N.M) { $(D_KEYWORD extern) (C++) { $(D_KEYWORD extern) (C++, R) { $(D_KEYWORD void) foo(); } } } N.M.R.foo(); ) $(DDOC_BLANKLINE ) $(P refers to the C++ declaration:) $(DDOC_BLANKLINE ) $(CPPCODE namespace N { namespace M { namespace R { void foo(); } } }) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 align, $(D align) Attribute)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AlignAttribute): $(D align) $(D align) $(D $(LPAREN)) $(GLINK2 expression, AssignExpression) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(P Specifies the alignment of:) $(DDOC_BLANKLINE ) $(OL $(LI variables) $(LI struct fields) $(LI union fields) $(LI class fields) $(LI struct, union, and class types) ) $(DDOC_BLANKLINE ) $(P $(D align) by itself sets it to the default, which matches the default member alignment of the companion C compiler.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD align): $(D_KEYWORD byte) a; $(D_COMMENT // placed at offset 0 ) $(D_KEYWORD int) b; $(D_COMMENT // placed at offset 4 ) $(D_KEYWORD long) c; $(D_COMMENT // placed at offset 8 )} $(D_KEYWORD static) $(D_KEYWORD assert)(S.alignof == 8); $(D_KEYWORD static) $(D_KEYWORD assert)(S.c.offsetof == 8); $(D_KEYWORD static) $(D_KEYWORD assert)(S.sizeof == 16); ) ) $(P The $(I AssignExpression) specifies the alignment which matches the behavior of the companion C compiler when non-default alignments are used. It must be a non-negative power of 2. ) $(DDOC_BLANKLINE ) $(P A value of 1 means that no alignment is done; fields are packed together. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD align) (1): $(D_KEYWORD byte) a; $(D_COMMENT // placed at offset 0 ) $(D_KEYWORD int) b; $(D_COMMENT // placed at offset 1 ) $(D_KEYWORD long) c; $(D_COMMENT // placed at offset 5 )} $(D_KEYWORD static) $(D_KEYWORD assert)(S.alignof == 1); $(D_KEYWORD static) $(D_KEYWORD assert)(S.c.offsetof == 5); $(D_KEYWORD static) $(D_KEYWORD assert)(S.sizeof == 13); ) ) $(P The natural alignment of an aggregate is the maximum alignment of its fields. It can be overridden by setting the alignment outside of the aggregate.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD align) (2) $(D_KEYWORD struct) S { $(D_KEYWORD align) (1): $(D_KEYWORD byte) a; $(D_COMMENT // placed at offset 0 ) $(D_KEYWORD int) b; $(D_COMMENT // placed at offset 1 ) $(D_KEYWORD long) c; $(D_COMMENT // placed at offset 5 )} $(D_KEYWORD static) $(D_KEYWORD assert)(S.alignof == 2); $(D_KEYWORD static) $(D_KEYWORD assert)(S.c.offsetof == 5); $(D_KEYWORD static) $(D_KEYWORD assert)(S.sizeof == 14); ) ) $(P Setting the alignment of a field aligns it to that power of 2, regardless of the size of the field.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD byte) a; $(D_COMMENT // placed at offset 0 ) $(D_KEYWORD align) (4) $(D_KEYWORD byte) b; $(D_COMMENT // placed at offset 4 ) $(D_KEYWORD align) (16) $(D_KEYWORD short) c; $(D_COMMENT // placed at offset 16 )} $(D_KEYWORD static) $(D_KEYWORD assert)(S.alignof == 16); $(D_KEYWORD static) $(D_KEYWORD assert)(S.c.offsetof == 16); $(D_KEYWORD static) $(D_KEYWORD assert)(S.sizeof == 32); ) ) $(P The $(I AlignAttribute) is reset to the default when entering a function scope or a non-anonymous struct, union, class, and restored when exiting that scope. It is not inherited from a base class. ) $(DDOC_BLANKLINE ) $(P See also: $(DDSUBLINK spec/struct, struct_layout, Struct Layout).) $(DDOC_BLANKLINE )

$(LNAME2 align_gc, GC Compatibility)

$(DDOC_BLANKLINE ) $(P Do not align references or pointers that were allocated using $(GLINK2 expression, NewExpression) on boundaries that are not a multiple of $(D size_t). The garbage collector assumes that pointers and references to GC allocated objects will be on $(D size_t) byte boundaries. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD align)(1): $(D_KEYWORD byte) b; $(D_KEYWORD int)* p; } $(D_KEYWORD static) $(D_KEYWORD assert)(S.p.offsetof == 1); @safe $(D_KEYWORD void) main() { S s; s.p = $(D_KEYWORD new) $(D_KEYWORD int); $(D_COMMENT // error: can't modify misaligned pointer in @safe code )} ) ) $(UNDEFINED_BEHAVIOR If any pointers and references to GC allocated objects are not aligned on size_t byte boundaries.) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 deprecated, $(D deprecated) Attribute)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME DeprecatedAttribute): $(D deprecated) $(D deprecated $(LPAREN)) $(GLINK2 expression, AssignExpression) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P It is often necessary to deprecate a feature in a library, yet retain it for backwards compatibility. Such declarations can be marked as $(D deprecated), which means that the compiler can be instructed to produce an error if any code refers to deprecated declarations: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD deprecated) { $(D_KEYWORD void) oldFoo(); } oldFoo(); $(D_COMMENT // Deprecated: function test.oldFoo is deprecated ))$(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(P Optionally a string literal or manifest constant can be used to provide additional information in the deprecation message. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD deprecated)($(D_STRING "Don't use bar")) $(D_KEYWORD void) oldBar(); oldBar(); $(D_COMMENT // Deprecated: function test.oldBar is deprecated - Don't use bar )) $(DDOC_BLANKLINE ) $(P Calling CTFE-able functions or using manifest constants is also possible. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.format; $(D_KEYWORD enum) message = format($(D_STRING "%s and all its members are obsolete"), Foobar.stringof); $(D_KEYWORD deprecated)(message) $(D_KEYWORD class) Foobar {} $(D_KEYWORD deprecated)(format($(D_STRING "%s is also obsolete"), $(D_STRING "This class"))) $(D_KEYWORD class) BarFoo {} $(D_KEYWORD void) main() { $(D_KEYWORD auto) fb = $(D_KEYWORD new) Foobar(); $(D_COMMENT // Deprecated: class test.Foobar is deprecated - Foobar ) $(D_COMMENT // and all its members are obsolete ) $(D_KEYWORD auto) bf = $(D_KEYWORD new) BarFoo(); $(D_COMMENT // Deprecated: class test.BarFoo is deprecated - This ) $(D_COMMENT // class is also obsolete )} ) ) $(DDOC_BLANKLINE ) $(P $(B Implementation Note:) The compiler should have a switch specifying if $(D deprecated) should be ignored, cause a warning, or cause an error during compilation. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 visibility_attributes, Visibility Attribute)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME VisibilityAttribute): $(D export) $(D package) $(D package) $(D $(LPAREN)) $(GLINK2 type, QualifiedIdentifier) $(D $(RPAREN )) $(D private) $(D protected) $(D public) ) $(DDOC_BLANKLINE ) $(P Visibility is an attribute that is one of $(D private), $(D package), protected, $(D public), or $(D export). They may be referred to as protection attributes in documents predating $(LINK2 http://wiki.dlang.org/DIP22, DIP22).) $(DDOC_BLANKLINE ) $(P Visibility participates in $(DDSUBLINK spec/module, name_lookup, symbol name lookup). ) $(DDOC_BLANKLINE )

$(LNAME2 export, $(D export) Attribute)

$(DDOC_BLANKLINE ) $(P $(D export) means that a symbol can be accessed from outside the executable, shared library, or DLL. The symbol is said to be exported from where it is defined in an executable, shared library, or DLL, and imported by another executable, shared library, or DLL.) $(DDOC_BLANKLINE ) $(P $(D export) applied to the definition of a symbol will export it. $(D export) applied to a declaration of a symbol will import it. A variable is a definition unless extern is applied to it.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD export) $(D_KEYWORD int) x = 3; $(D_COMMENT // definition, exporting `x` )$(D_KEYWORD export) $(D_KEYWORD int) y; $(D_COMMENT // definition, exporting `y` )$(D_KEYWORD export) $(D_KEYWORD extern) $(D_KEYWORD int) z; $(D_COMMENT // declaration, importing `z` ) $(D_KEYWORD export) $(D_KEYWORD __gshared) h = 3; $(D_COMMENT // definition, exporting `h` )$(D_KEYWORD export) $(D_KEYWORD __gshared) i; $(D_COMMENT // definition, exporting `i` )$(D_KEYWORD export) $(D_KEYWORD extern) $(D_KEYWORD __gshared) $(D_KEYWORD int) j; $(D_COMMENT // declaration, importing `j` )) $(DDOC_BLANKLINE ) $(P A function with a body is a definition, without a body is a declaration.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD export) $(D_KEYWORD void) f() { } $(D_COMMENT // definition, exporting `f` )$(D_KEYWORD export) $(D_KEYWORD void) g(); $(D_COMMENT // declaration, importing `g` )) $(DDOC_BLANKLINE ) $(P In Windows terminology, $(I dllexport) means exporting a symbol from a DLL, and $(I dllimport) means a DLL or executable is importing a symbol from a DLL.) $(DDOC_BLANKLINE )

$(LNAME2 package, $(D package) Attribute)

$(DDOC_BLANKLINE ) $(P $(D package) extends $(D private) so that package members can be accessed from code in other modules that are in the same package. If no identifier is provided, this applies to the innermost package only, or defaults to $(D private) if a module is not nested in a package. ) $(DDOC_BLANKLINE ) $(P $(D package) may have an optional parameter in the form of a dot-separated identifier list which is resolved as the qualified package name. The package must be either the module's parent package or one of its ancestors. If this parameter is present, the symbol will be visible in the specified package and all of its descendants. ) $(DDOC_BLANKLINE )

$(LNAME2 private, $(D private) Attribute)

$(DDOC_BLANKLINE ) $(P Symbols with $(D private) visibility can only be accessed from within the same module. Private member functions are implicitly $(DDSUBLINK spec/function, final, final) and cannot be overridden. ) $(DDOC_BLANKLINE )

$(LNAME2 protected, $(D protected) Attribute)

$(DDOC_BLANKLINE ) $(P $(D protected) only applies inside classes (and templates as they can be mixed in) and means that a symbol can only be seen by members of the same module, or by a derived class. If accessing a protected instance member through a derived class member function, that member can only be accessed for the object instance which can be implicitly cast to the same type as $(SINGLEQUOTE this). $(D protected) module members are illegal. ) $(DDOC_BLANKLINE )

$(LNAME2 public, $(D public) Attribute)

$(DDOC_BLANKLINE ) $(P $(D public) means that any code within the executable can see the member. It is the default visibility attribute. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 mutability, Mutability Attributes)

$(DDOC_BLANKLINE )

$(LNAME2 const, $(D const) Attribute)

$(DDOC_BLANKLINE ) $(P The $(DDLINK spec/const3, Type Qualifiers, $(D const) type qualifier) changes the type of the declared symbol from $(D T) to $(D const(T)), where $(D T) is the type specified (or inferred) for the introduced symbol in the absence of $(D const). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD const) $(D_KEYWORD int) foo = 7; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(foo) == $(D_KEYWORD const)($(D_KEYWORD int)))); $(D_KEYWORD const) $(D_KEYWORD double) bar = foo + 6; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(bar) == $(D_KEYWORD const)($(D_KEYWORD double)))); ) ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD const) $(D_KEYWORD void) foo(); $(D_KEYWORD const) { $(D_KEYWORD void) bar(); } $(D_KEYWORD void) baz() $(D_KEYWORD const); } $(D_KEYWORD pragma)(msg, $(D_KEYWORD typeof)(C.foo)); $(D_COMMENT // const void$(LPAREN)$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD typeof)(C.bar)); $(D_COMMENT // const void$(LPAREN)$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD typeof)(C.baz)); $(D_COMMENT // const void$(LPAREN)$(RPAREN ) ) $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(C.foo) == $(D_KEYWORD typeof)(C.bar)) && $(D_KEYWORD is)($(D_KEYWORD typeof)(C.bar) == $(D_KEYWORD typeof)(C.baz))); ) ) $(DDOC_BLANKLINE ) $(P See also: $(DDSUBLINK spec/declaration, methods-returning-qualified, Methods Returning a Qualified Type).) $(DDOC_BLANKLINE )

$(LNAME2 immutable, $(D immutable) Attribute)

$(DDOC_BLANKLINE ) $(P The $(D immutable) attribute modifies the type from $(D T) to $(D immutable(T)), the same way as $(D const) does. See: ) $(UL $(LI $(DDSUBLINK spec/const3, immutable_storage_class, immutable storage class)) $(LI $(DDSUBLINK spec/const3, immutable_type, $(D immutable) type qualifier) ) )

$(LNAME2 inout, $(D inout) Attribute)

$(DDOC_BLANKLINE ) $(P The $(DDSUBLINK spec/const3, inout, $(D inout) attribute) modifies the type from $(D T) to $(D inout(T)), the same way as $(D const) does. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 shared-storage, Shared Storage Attributes)

$(DDOC_BLANKLINE )

$(LNAME2 shared, $(D shared) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/const3, shared, $(D shared)).) $(DDOC_BLANKLINE )

$(LNAME2 gshared, $(D __gshared) Attribute)

$(DDOC_BLANKLINE ) $(P By default, non-immutable global declarations reside in thread local storage. When a global variable is marked with the $(D __gshared) attribute, its value is shared across all threads.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) foo; $(D_COMMENT // Each thread has its own exclusive copy of foo. )$(D_KEYWORD __gshared) $(D_KEYWORD int) bar; $(D_COMMENT // bar is shared by all threads. )) $(DDOC_BLANKLINE ) $(P $(D __gshared) may also be applied to member variables and local variables. In these cases, $(D __gshared) is equivalent to $(D static), except that the variable is shared by all threads rather than being thread local.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD __gshared) $(D_KEYWORD int) bar; } $(D_KEYWORD int) foo() { $(D_KEYWORD __gshared) $(D_KEYWORD int) bar = 0; $(D_KEYWORD return) bar++; $(D_COMMENT // Not thread safe. )} ) $(DDOC_BLANKLINE ) $(P $(RED Warning:) Unlike the $(RELATIVE_LINK2 shared, shared) attribute, $(D __gshared) provides no safeguards against data races or other multi-threaded synchronization issues. It is the responsibility of the programmer to ensure that access to variables marked $(D __gshared) is synchronized correctly.) $(DDOC_BLANKLINE ) $(P $(D __gshared) is disallowed in @safe code.) $(DDOC_BLANKLINE )

$(LNAME2 synchronized, $(D @synchronized) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/class, synchronized-classes, Synchronized Classes).) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 disable, $(D @disable) Attribute)

$(DDOC_BLANKLINE ) $(P A reference to a declaration marked with the $(CODE @disable) attribute causes a compile time error. This can be used to explicitly disallow certain operations or overloads at compile time rather than relying on generating a runtime error.) $(DDOC_BLANKLINE ) $(D_CODE @disable $(D_KEYWORD void) foo() { } ) $(D_CODE $(D_KEYWORD void) main() { foo(); $(D_COMMENT /* error, foo is disabled */) } ) $(DDOC_BLANKLINE ) $(P $(DDSUBLINK spec/struct, disable_default_construction, @disable this();) inside a struct disallows default construction. ) $(DDOC_BLANKLINE ) $(P $(DDSUBLINK spec/struct, disable-copy, Disabling a struct copy constructor) makes the struct not copyable. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 safe, $(D @safe), $(D @trusted), and $(D @system) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, function-safety, Function Safety).) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 function-attributes, Function Attributes)

$(DDOC_BLANKLINE )

$(LNAME2 nogc, $(D @nogc) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, nogc-functions, No-GC Functions).) $(DDOC_BLANKLINE )

$(LNAME2 property, $(D @property) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, property-functions, Property Functions).) $(DDOC_BLANKLINE )

$(LNAME2 nothrow, $(D nothrow) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, nothrow-functions, Nothrow Functions).) $(DDOC_BLANKLINE )

$(LNAME2 pure, $(D pure) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, pure-functions, Pure Functions).) $(DDOC_BLANKLINE )

$(LNAME2 ref, $(D ref) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/declaration, ref-storage, ref Storage Class).) $(DDOC_BLANKLINE )

$(LNAME2 return, $(D return) Attribute)

$(UL $(LI $(DDSUBLINK spec/function, return-ref-parameters, Return Ref Parameters).) $(LI $(DDSUBLINK spec/function, return-scope-parameters, Return Scope Parameters). ) )

$(LNAME2 static, $(D static) Attribute)

$(DDOC_BLANKLINE ) $(P The $(D static) attribute applies to types, functions and data. $(D static) is ignored when applied to other declarations.) $(DDOC_BLANKLINE ) $(P Inside an aggregate type, a static declaration does not apply to a particular instance of an object, but to the type of the object. In other words, it means there is no $(D this) reference. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) $(D_KEYWORD int) x; $(D_KEYWORD static) $(D_KEYWORD int) bar() { $(D_KEYWORD return) x; } $(D_KEYWORD int) foobar() { $(D_KEYWORD return) 7; } } Foo.x = 6; $(D_COMMENT // no instance needed )$(D_KEYWORD assert)(Foo.bar() == 6); $(D_COMMENT //Foo.foobar$(LPAREN)$(RPAREN ); // error, no instance of Foo ) Foo f = $(D_KEYWORD new) Foo; $(D_KEYWORD assert)(f.bar() == 6); $(D_KEYWORD assert)(f.foobar() == 7); ) ) $(DDOC_BLANKLINE ) $(P Static methods are never $(DDSUBLINK spec/function, virtual-functions, virtual). ) $(P Static data has one instance per thread, not one per object. ) $(DDOC_BLANKLINE ) $(P A static $(DDSUBLINK spec/function, nested, nested function) or $(DDSUBLINK spec/struct, nested, type) cannot access variables in the parent scope.) $(DDOC_BLANKLINE ) $(P Inside a function, a $(DDSUBLINK spec/function, local-static-variables, static local variable) persists after the function returns.) $(DDOC_BLANKLINE ) $(P Static does not have the additional C meaning of being local to a file. Use the $(RELATIVE_LINK2 VisibilityAttribute, private) attribute in D to achieve that. For example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD module) foo; $(D_KEYWORD int) x = 3; $(D_COMMENT // x is global )$(D_KEYWORD private) $(D_KEYWORD int) y = 4; $(D_COMMENT // y is local to module foo )) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 auto, $(D auto) Attribute)

$(DDOC_BLANKLINE ) $(P The $(D auto) attribute is used when there are no other attributes and $(DDSUBLINK spec/declaration, auto-declaration, type inference) is desired. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) i = 6.8; $(D_COMMENT // declare i as a double )) $(DDOC_BLANKLINE ) $(P For functions, the auto attribute means return type inference. See $(DDSUBLINK spec/function, auto-functions, Auto Functions). ) $(DDOC_BLANKLINE )

$(LNAME2 scope, $(D scope) Attribute)

$(DDOC_BLANKLINE ) $(P The scope attribute signifies a variable's pointer values will not escape the scope that the variable is declared in. ) $(DDOC_BLANKLINE ) $(P If the variable has a type that does not contain any indirections, the scope attribute is ignored. ) $(DDOC_BLANKLINE ) $(P When applied to a global variable, scope is also ignored, since there is no scope larger than global scope that pointers could escape to. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD scope) $(D_KEYWORD int)* x; $(D_COMMENT // scope ignored, global variable ) $(D_KEYWORD void) main() { $(D_COMMENT // scope static int* x; // cannot be both scope and static ) $(D_KEYWORD scope) $(D_KEYWORD float) y; $(D_COMMENT // scope ignored, no indirections ) $(D_KEYWORD scope) $(D_KEYWORD int)[2] z; $(D_COMMENT // scope ignored, static array is value type ) $(D_KEYWORD scope) $(D_KEYWORD int)[] w; $(D_COMMENT // scope dynamic array )} ) ) $(DDOC_BLANKLINE ) $(P When applied to a local variable with a type that has indirections, its value may not be assigned to a variable with longer lifetime: ) $(UL $(LI Variables outside the $(DDSUBLINK spec/statement, scope-statement, Scope Statement) that the variable is declared in) $(LI Variables declared before the scope variable, since local variables are destructed in the reverse order that they are declared in) $(LI __gshared or static variables) ) $(DDOC_BLANKLINE ) $(P Other operations implicitly assigning them to variables with longer lifetime are also disallowed: ) $(UL $(LI Returning a scope variable from a function) $(LI Assigning a scope variable to a non-scope parameter by calling a function) $(LI Putting a scope variable in an array literal) ) $(P The scope attribute is part of the variable declaration, not the type, and it only applies to the first level of indirection. For example, it is impossible to declare a variable as a dynamic array of scope pointers, because scope only applies to the .ptr of the array itself, not its elements. scope affects various types as follows: ) $(DDOC_BLANKLINE ) $(TABLE_2COLS , Type of local variable, What scope applies to $(DDOC_BLANKLINE ) $(TROW Any $(DDSUBLINK spec/type, basic-data-types, Basic Data Type), nothing) $(TROW $(DDSUBLINK spec/type, pointers, Pointer) T*, the pointer value) $(TROW $(DDSUBLINK spec/arrays, dynamic-arrays, Dynamic Array) T[], the .ptr to the elements) $(TROW $(DDSUBLINK spec/arrays, static-arrays, Static Array) T[n], each element T) $(TROW $(GLINK2 hash-map, Associative Array) K[V], the pointer to the implementation defined structure) $(TROW struct or union, each of its member variables) $(TROW function pointer, the pointer value) $(TROW $(DDSUBLINK spec/function, closures, delegate), both the .funcptr and .ptr (closure context) pointer values) $(TROW class or interface, the class reference) $(TROW $(GLINK2 enum, enum), the base type) ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD struct) S { string str; $(D_COMMENT // note: string = immutable$(LPAREN)char$(RPAREN )[] ) string* strPtr; } string escape($(D_KEYWORD scope) S s, $(D_KEYWORD scope) S* sPtr, $(D_KEYWORD scope) string[2] sarray, $(D_KEYWORD scope) string[] darray) { $(D_KEYWORD return) s.str; $(D_COMMENT // invalid, scope applies to struct members ) $(D_KEYWORD return) *s.strPtr; $(D_COMMENT // valid, scope struct member is dereferenced ) $(D_KEYWORD return) sPtr.str; $(D_COMMENT // valid, struct pointer is dereferenced ) $(D_KEYWORD return) *sPtr.strPtr; $(D_COMMENT // valid, two pointers are dereferenced ) $(D_KEYWORD return) sarray[0]; $(D_COMMENT // invalid, scope applies to static array elements ) $(D_KEYWORD return) sarray[1]; $(D_COMMENT // invalid, ditto ) $(D_KEYWORD return) darray[0]; $(D_COMMENT // valid, scope applies to array pointer, not elements )} ) $(DDOC_BLANKLINE )

$(LNAME2 scope-values, Scope Values)

$(DDOC_BLANKLINE ) $(P A "scope value" is the value of a scope variable, or a generated value pointing to stack allocated memory. Such values are generated by $(DDSUBLINK spec/arrays, slicing, slicing) a static array or creating $(DDSUBLINK spec/type, pointers, a pointer) to a variable that is (or may be) allocated on the stack: ) $(UL $(LI A function parameter) $(LI A local variable) $(LI A struct member accessed through the implicit this parameter) $(LI The return value of a $(DDSUBLINK spec/function, ref-functions, Ref Function)) ) $(DDOC_BLANKLINE ) $(P The variadic parameter from $(DDSUBLINK spec/function, typesafe_variadic_functions, Typesafe Variadic Functions) is also a scope value, since the arguments are passed on the stack. ) $(DDOC_BLANKLINE ) $(P When a local variable is assigned a scope value, it is inferred scope, even when the variable has an explicit type and does not use the auto keyword. ) $(DDOC_BLANKLINE ) $(D_CODE @safe: $(D_KEYWORD ref) $(D_KEYWORD int)[2] identity($(D_KEYWORD return) $(D_KEYWORD ref) $(D_KEYWORD int)[2] x) {$(D_KEYWORD return) x;} $(D_KEYWORD int)* escape($(D_KEYWORD int)[2] y, $(D_KEYWORD scope) $(D_KEYWORD int)* z) { $(D_KEYWORD int) x; $(D_KEYWORD auto) xPtr = &x; $(D_COMMENT // inferred `scope int*` ) $(D_KEYWORD int)[] yArr = identity(y)[]; $(D_COMMENT // inferred `scope int[]` ) $(D_KEYWORD int)* zCopy = z; $(D_COMMENT // inferred `scope int*` ) $(D_KEYWORD return) zCopy; $(D_COMMENT // error )} $(D_KEYWORD void) variadic($(D_KEYWORD int)[] a...) { $(D_KEYWORD int)[] x = a; $(D_COMMENT // inferred `scope int[]` )} $(D_KEYWORD void) main() { variadic(1, 2, 3); } ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD int) x; $(D_COMMENT // this method may be called on a stack-allocated instance of S ) $(D_KEYWORD void) f() { $(D_KEYWORD int)* p = &x; $(D_COMMENT // inferred `scope int* p` ) $(D_KEYWORD int)* q = &$(D_KEYWORD this).x; $(D_COMMENT // equivalent ) } } ) ) $(DDOC_BLANKLINE ) $(P $(DDSUBLINK spec/function, scope-parameters, Scope Parameters) are treated the same as scope local variables, except that returning them is allowed when the function has $(DDSUBLINK spec/function, function-attribute-inference, Function Attribute Inference). In that case, they are inferred as $(DDSUBLINK spec/function, return-scope-parameters, Return Scope Parameters). ) $(DDOC_BLANKLINE )

$(LNAME2 scope-class-var, $(D scope) Class Instances)

$(P When used to allocate a class instance directly, a scope variable signifies the RAII (Resource Acquisition Is Initialization) protocol. This means that the destructor for an object is automatically called when the reference to it goes out of scope. The destructor is called even if the scope is exited via a thrown exception, thus $(D scope) is used to guarantee cleanup. ) $(P When a class is constructed with new and assigned to a local scope variable, it may be allocated on the stack and permitted in a @nogc context. ) $(P If there is more than one scope class variable going out of scope at the same point, then the destructors are called in the reverse order that the variables were constructed. ) $(P Assignment to a $(D scope) variable with class type, other than initialization, is not allowed, because that would complicate proper destruction of the variable. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) core.stdc.stdio : puts; $(D_KEYWORD class) C { ~$(D_KEYWORD this)() @nogc { puts($(D_KEYWORD __FUNCTION__)); } } $(D_KEYWORD void) main() @nogc { { $(D_KEYWORD scope) c0 = $(D_KEYWORD new) C(); $(D_COMMENT // allocated on the stack ) $(D_KEYWORD scope) c1 = $(D_KEYWORD new) C(); $(D_COMMENT //c1 = c0; // Error: cannot rebind scope variables ) $(D_COMMENT // destructor of `c1` and `c0` are called here in that order ) } puts($(D_STRING "bye")); } ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 class-attributes, OOP Attributes)

$(DDOC_BLANKLINE )

$(LNAME2 abstract, $(D abstract) Attribute)

$(DDOC_BLANKLINE ) $(P An $(DDSUBLINK spec/class, abstract, abstract class) must be overridden by a derived class. Declaring an abstract member function makes the class abstract. ) $(DDOC_BLANKLINE )

$(LNAME2 final, final Attribute)

$(DDOC_BLANKLINE ) $(UL $(LI A class can be declared $(DDSUBLINK spec/class, final, final) to prevent subclassing.) $(LI A class method can be declared $(DDSUBLINK spec/function, final, final) to prevent a derived class overriding it.) $(LI Interfaces can define $(DDSUBLINK spec/interface, method-bodies, final methods).) ) $(DDOC_BLANKLINE )

$(LNAME2 override, $(D override) Attribute)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/function, virtual-functions, Virtual Functions).) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 mustuse-attribute, @mustuse Attribute)

$(DDOC_BLANKLINE ) $(P The @mustuse attribute is a compiler-recognized $(RELATIVE_LINK2 uda, UDA) defined in the D runtime module $(DPLLINK phobos/core_attribute.html, core.attribute). ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(P An expression is considered to be discarded if and only if either of the following is true: ) $(UL $(LI it is the top-level $(GLINK2 expression, Expression) in an $(GLINK2 statement, ExpressionStatement), or ) $(LI it is the $(GLINK2 expression, AssignExpression) on the left-hand side of the comma in a $(GLINK2 expression, CommaExpression). ) ) $(DDOC_BLANKLINE ) $(P It is a compile-time error to discard an expression if all of the following are true: ) $(DDOC_BLANKLINE ) $(UL $(LI it is not an assignment expression, an increment expression, or a decrement expression; and ) $(DDOC_BLANKLINE ) $(LI its type is a struct or union type whose declaration is annotated with @mustuse. ) ) $(DDOC_BLANKLINE ) $(P "Assignment expression" means either a $(DDSUBLINK spec/expression, simple_assignment_expressions, simple assignment expression) or an $(DDSUBLINK spec/expression, assignment_operator_expressions, assignment operator expression). ) $(DDOC_BLANKLINE ) $(P "Increment expression" means a $(GLINK2 expression, UnaryExpression) or $(GLINK2 expression, PostfixExpression) whose operator is ++. ) $(DDOC_BLANKLINE ) $(P "Decrement expression" means a $(GLINK2 expression, UnaryExpression) or $(GLINK2 expression, PostfixExpression) whose operator is --. ) $(DDOC_BLANKLINE ) $(P It is a compile-time error to attach @mustuse to a function declaration or to any aggregate declaration other than a struct or union declaration. The purpose of this rule is to reserve such usage for possible future expansion. ) $(DDOC_BLANKLINE )

$(LNAME2 uda, User-Defined Attributes)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME UserDefinedAttribute): $(D @ $(LPAREN)) $(GLINK2 expression, TemplateArgumentList) $(D $(RPAREN )) $(D @) $(GLINK2 template, TemplateSingleArgument) $(D @) $(GLINK_LEX Identifier) $(D $(LPAREN)) $(GLINK2 expression, NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(D @) $(GLINK2 template, TemplateInstance) $(D @) $(GLINK2 template, TemplateInstance) $(D $(LPAREN)) $(GLINK2 expression, NamedArgumentList)$(OPT ) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P User-Defined Attributes (UDA) are compile-time annotations 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. ) $(DDOC_BLANKLINE ) A user-defined attribute is defined using: $(UL $(LI Compile-time expressions) $(LI A named manifest constant) $(LI A type name) $(LI A type to instantiate using a compile-time argument list ) ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE @(3) $(D_KEYWORD int) a; $(D_COMMENT // value argument )@($(D_STRING "string"), 7) $(D_KEYWORD int) b; $(D_COMMENT // multiple values ) $(D_COMMENT // using compile-time constant )$(D_KEYWORD enum) val = 3; @val $(D_KEYWORD int) a2; $(D_COMMENT // has same attribute as `a` ) $(D_KEYWORD enum) Foo; @Foo $(D_KEYWORD int) c; $(D_COMMENT // type name attribute ) $(D_KEYWORD struct) Bar { $(D_KEYWORD int) x; } @Bar() $(D_KEYWORD int) d; $(D_COMMENT // type instance )@Bar(3) $(D_KEYWORD int) e; $(D_COMMENT // type instance using initializer )) ) $(P For e, the attribute is an instance of struct Bar which is $(DDSUBLINK spec/struct, static_struct_init, statically initialized) using its argument.) $(DDOC_BLANKLINE ) $(P If there are multiple UDAs in scope for a declaration, they are concatenated: ) $(DDOC_BLANKLINE ) $(D_CODE @(1) { @(2) $(D_KEYWORD int) a; $(D_COMMENT // has UDAs $(LPAREN)1, 2$(RPAREN ) ) @($(D_STRING "string")) $(D_KEYWORD int) b; $(D_COMMENT // has UDAs $(LPAREN)1, "string"$(RPAREN ) )} ) $(DDOC_BLANKLINE ) $(P A function parameter can have a UDA:) $(D_CODE $(D_KEYWORD void) f(@(3) $(D_KEYWORD int) p); ) $(DDOC_BLANKLINE )

$(LNAME2 getAttributes, __traits(getAttributes))

$(DDOC_BLANKLINE ) $(P UDAs can be extracted into a $(DDSUBLINK spec/template, variadic-templates, compile-time sequence) using $(D __traits): ) $(DDOC_BLANKLINE ) $(D_CODE @('c') string s; $(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, s)); $(D_COMMENT // prints tuple$(LPAREN)'c'$(RPAREN ) )) $(DDOC_BLANKLINE ) $(P If there are no user-defined attributes for the symbol, an empty sequence is returned. The result can be used just like any compile-time sequence - it can be indexed, passed as template parameters, etc. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD enum) e = 7; @($(D_STRING "hello")) $(D_KEYWORD struct) SSS { } @(3) { @(4) @e @SSS $(D_KEYWORD int) foo; } $(D_KEYWORD alias) TP = $(D_KEYWORD __traits)(getAttributes, foo); $(D_KEYWORD pragma)(msg, TP); $(D_COMMENT // prints tuple$(LPAREN)3, 4, 7, $(LPAREN)SSS$(RPAREN )$(RPAREN ) )$(D_KEYWORD pragma)(msg, TP[2]); $(D_COMMENT // prints 7 )) ) $(DDOC_BLANKLINE ) $(P Any types in the sequence can be used to declare things: ) $(DDOC_BLANKLINE ) $(D_CODE TP[3] a; $(D_COMMENT // a is declared as an SSS )) $(DDOC_BLANKLINE ) $(P The attribute of the type name is not the same as the attribute of the variable: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, a)); $(D_COMMENT // prints tuple$(LPAREN)$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, $(D_KEYWORD typeof)(a))); $(D_COMMENT // prints tuple$(LPAREN)"hello"$(RPAREN ) )) $(DDOC_BLANKLINE )

$(LNAME2 uda-usage, Usage)

$(DDOC_BLANKLINE ) $(P Of course, the real value of UDAs is to be able to create user-defined types with specific values. Having attribute values of basic types does not scale. ) $(DDOC_BLANKLINE ) $(P 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. ) $(DDOC_BLANKLINE )

$(LNAME2 uda-templates, Templates)

$(DDOC_BLANKLINE ) $(P If a UDA is attached to a template declaration, then it will be automatically attached to all direct members of instances of that template. If any of those members are templates themselves, this rule applies recursively: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE @($(D_STRING "foo")) $(D_KEYWORD template) Outer(T) { $(D_KEYWORD struct) S { $(D_KEYWORD int) x; } $(D_KEYWORD int) y; $(D_KEYWORD void) fun() {} @($(D_STRING "bar")) $(D_KEYWORD template) Inner(U) { $(D_KEYWORD int) z; } } $(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).S)); $(D_COMMENT // prints tuple$(LPAREN)"foo"$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).S.x)); $(D_COMMENT // prints tuple$(LPAREN)$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).y)); $(D_COMMENT // prints tuple$(LPAREN)"foo"$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).fun)); $(D_COMMENT // prints tuple$(LPAREN)"foo"$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).Inner)); $(D_COMMENT // prints tuple$(LPAREN)"foo", "bar"$(RPAREN ) )$(D_KEYWORD pragma)(msg, $(D_KEYWORD __traits)(getAttributes, Outer!$(D_KEYWORD int).Inner!$(D_KEYWORD int).z)); $(D_COMMENT // prints tuple$(LPAREN)"foo", "bar"$(RPAREN ) )) ) $(DDOC_BLANKLINE ) $(P UDAs cannot be attached to template parameters. ) $(SPEC_SUBNAV_PREV_NEXT property, Properties, pragma, Pragmas) ) )