$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Declarations, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_SUBITEMS grammar, Grammar, $(HEADERNAV_ITEM aggregates, Aggregates) $(HEADERNAV_ITEM variable-declarations, Variable Declarations) $(HEADERNAV_ITEM storage-classes, Storage Classes) $(HEADERNAV_ITEM initializers, Initializers) ) $(HEADERNAV_SUBITEMS declaration_syntax, Declaration Syntax, $(HEADERNAV_ITEM pointers-to-functions, Function Pointers) $(HEADERNAV_ITEM c-style-declarations, C-Style Declarations) $(HEADERNAV_ITEM declaring-multiple-symbols, Declaring Multiple Symbols) ) $(HEADERNAV_ITEM auto-declaration, Implicit Type Inference) $(HEADERNAV_SUBITEMS alias, Alias Declarations, $(HEADERNAV_ITEM alias-type, Type Aliases) $(HEADERNAV_ITEM alias-symbol, Symbol Aliases) $(HEADERNAV_ITEM alias-overload, Aliasing an Overload Set) $(HEADERNAV_ITEM alias-variable, Aliasing Variables) $(HEADERNAV_ITEM alias-function, Aliasing a Function Type) $(HEADERNAV_ITEM AliasAssign, Alias Assign) $(HEADERNAV_ITEM alias-reassignment, Alias Reassignment) ) $(HEADERNAV_ITEM extern, Extern Declarations) $(HEADERNAV_ITEM void_init, Void Initializations) $(HEADERNAV_ITEM global_static_init, Global and Static Initializers) $(HEADERNAV_SUBITEMS typequal_vs_storageclass, Type Qualifiers vs. Storage Classes, $(HEADERNAV_ITEM ref-storage, ref Storage Class) $(HEADERNAV_ITEM methods-returning-qualified, Methods Returning a Qualified Type) ) ) $(DDOC_BLANKLINE )

$(LNAME2 grammar, Grammar)

$(DDOC_BLANKLINE ) $(P Declaration can be used inside a function body for a $(GLINK2 statement, DeclarationStatement), as well as outside a function as it is included in $(GLINK2 module, DeclDef).) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Declaration): $(GLINK2 function, FuncDeclaration) $(GLINK VarDeclarations) $(GLINK AliasDeclaration) $(GLINK AliasAssign) $(GLINK AggregateDeclaration) $(GLINK2 enum, EnumDeclaration) $(GLINK2 module, ImportDeclaration) $(GLINK2 version, ConditionalDeclaration) $(GLINK2 version, StaticForeachDeclaration) $(GLINK2 version, StaticAssert) $(GLINK2 template, TemplateDeclaration) $(GLINK2 template-mixin, TemplateMixinDeclaration) $(GLINK2 template-mixin, TemplateMixin) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 aggregates, Aggregates)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AggregateDeclaration): $(GLINK2 class, ClassDeclaration) $(GLINK2 interface, InterfaceDeclaration) $(GLINK2 struct, StructDeclaration) $(GLINK2 struct, UnionDeclaration) ) $(DDOC_BLANKLINE )

$(LNAME2 variable-declarations, Variable Declarations)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME VarDeclarations): $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 type, TypeSuffixes)$(OPT ) $(GLINK IdentifierInitializers) $(D ;) $(GLINK AutoDeclaration) $(DDOC_BLANKLINE ) $(GNAME IdentifierInitializers): $(LEGACY_LNAME2 Declarators, DeclaratorIdentifierList) $(GLINK IdentifierInitializer) $(GLINK IdentifierInitializer) $(D ,) $(GSELF IdentifierInitializers) $(DDOC_BLANKLINE ) $(GNAME IdentifierInitializer): $(LEGACY_LNAME2 DeclaratorInitializer, DeclaratorIdentifier) $(GLINK_LEX Identifier) $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT ) $(D =) $(GLINK Initializer) $(DDOC_BLANKLINE ) $(GNAME Declarator): $(LEGACY_LNAME2 VarDeclarator) $(GLINK2 type, TypeSuffixes)$(OPT ) $(GLINK_LEX Identifier) ) $(DDOC_BLANKLINE ) $(P See also:) $(UL $(LI $(RELATIVE_LINK2 declaration_syntax, Declaration Syntax)) $(LI $(GLINK AutoDeclaration)) $(LI $(DDSUBLINK spec/template, variable-template, Variable Templates) ) )

$(LNAME2 storage-classes, Storage Classes)

$(DDOC_BLANKLINE ) $(P See $(RELATIVE_LINK2 typequal_vs_storageclass, Type Classes vs. Storage Classes).) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StorageClasses): $(GLINK StorageClass) $(GLINK StorageClass) $(GSELF StorageClasses) $(DDOC_BLANKLINE ) $(GNAME StorageClass): $(GLINK2 attribute, LinkageAttribute) $(GLINK2 attribute, AlignAttribute) $(GLINK2 attribute, AtAttribute) $(DDSUBLINK spec/attribute, deprecated, deprecated) $(DDSUBLINK spec/enum, manifest_constants, enum) $(DDSUBLINK spec/attribute, static, static) $(RELATIVE_LINK2 extern, $(D extern)) $(DDSUBLINK spec/class, abstract, abstract) $(DDSUBLINK spec/class, final, final) $(DDSUBLINK spec/function, virtual-functions, override) $(DDSUBLINK spec/class, synchronized-classes, synchronized) $(RELATIVE_LINK2 auto-declaration, auto) $(DDSUBLINK spec/attribute, scope, scope) $(DDLINK spec/const3, Type Qualifiers, const) $(DDLINK spec/const3, Type Qualifiers, immutable) $(DDSUBLINK spec/const3, inout, inout) $(DDSUBLINK spec/const3, shared, shared) $(DDSUBLINK spec/attribute, gshared, __gshared) $(GLINK2 attribute, Property) $(DDSUBLINK spec/function, nothrow-functions, nothrow) $(DDSUBLINK spec/function, pure-functions, pure) $(RELATIVE_LINK2 ref-storage, ref) ) $(DDOC_BLANKLINE )

$(LNAME2 initializers, Initializers)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Initializer): $(GLINK VoidInitializer) $(GLINK NonVoidInitializer) $(DDOC_BLANKLINE ) $(GNAME NonVoidInitializer): $(GLINK2 expression, AssignExpression)$(LEGACY_LNAME2 ExpInitializer) $(GLINK2 expression, ArrayLiteral)$(LEGACY_LNAME2 ArrayInitializer) $(GLINK2 struct, StructInitializer)$(LEGACY_LNAME2 StructInitializer) ) $(DDOC_BLANKLINE ) $(P See also $(GLINK VoidInitializer).) $(DDOC_BLANKLINE )

$(LNAME2 declaration_syntax, Declaration Syntax)

$(DDOC_BLANKLINE ) $(P Declaration syntax generally reads right to left, including arrays:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) x; $(D_COMMENT // x is an int )$(D_KEYWORD int)* x; $(D_COMMENT // x is a pointer to int )$(D_KEYWORD int)** x; $(D_COMMENT // x is a pointer to a pointer to int ) $(D_KEYWORD int)[] x; $(D_COMMENT // x is an array of ints )$(D_KEYWORD int)*[] x; $(D_COMMENT // x is an array of pointers to ints )$(D_KEYWORD int)[]* x; $(D_COMMENT // x is a pointer to an array of ints ) $(D_KEYWORD int)[3] x; $(D_COMMENT // x is a static array of 3 ints )$(D_KEYWORD int)[3][5] x; $(D_COMMENT // x is a static array of 5 static arrays of 3 ints )$(D_KEYWORD int)[3]*[5] x; $(D_COMMENT // x is a static array of 5 pointers to static arrays of 3 ints )) $(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/type, pointers, Pointers), $(DDLINK spec/arrays, Arrays, Arrays) and $(GLINK2 type, TypeSuffix).) $(DDOC_BLANKLINE )

$(LNAME2 pointers-to-functions, Function Pointers)

$(DDOC_BLANKLINE ) $(P $(DDSUBLINK spec/function, function-pointers, Function Pointers) are declared using the $(D function) keyword: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD char)) x; $(D_COMMENT // x is a pointer to ) $(D_COMMENT // a function taking a char argument ) $(D_COMMENT // and returning an int )$(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD char))[] x; $(D_COMMENT // x is an array of ) $(D_COMMENT // pointers to functions ) $(D_COMMENT // taking a char argument ) $(D_COMMENT // and returning an int )) $(DDOC_BLANKLINE )

$(LNAME2 c-style-declarations, C-Style Declarations)

$(DDOC_BLANKLINE ) $(P C-style array, function pointer and pointer to array declarations are not supported. The following C declarations are for comparison only: ) $(DDOC_BLANKLINE ) $(CPPCODE int x[3]; // C static array of 3 ints int x[3][5]; // C static array of 3 arrays of 5 ints $(DDOC_BLANKLINE ) int (*x[5])[3]; // C static array of 5 pointers to static arrays of 3 ints int (*x)(char); // C pointer to a function taking a char argument // and returning an int int (*[] x)(char); // C array of pointers to functions // taking a char argument and returning an int ) $(DDOC_BLANKLINE ) $(RATIONALE $(UL $(LI In D types are straightforward to read from right to left, unlike in C where parentheses are sometimes required and the type is read iteratively using the clockwise/spiral rule.) $(LI For a C function pointer declaration a (*b)(c); a C parser needs to attempt a type lookup in order to parse it unambiguously - it could be a call to a function called a which returns a function pointer, which is immediately called. D function pointer syntax is unambiguous, avoiding the need for types to be forward declared.) ) ) $(DDOC_BLANKLINE )

$(LNAME2 declaring-multiple-symbols, Declaring Multiple Symbols)

$(DDOC_BLANKLINE ) $(P In a declaration declaring multiple symbols, all the declarations must be of the same type: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) x, y; $(D_COMMENT // x and y are ints )$(D_KEYWORD int)* x, y; $(D_COMMENT // x and y are pointers to ints )$(D_KEYWORD int)[] x, y; $(D_COMMENT // x and y are arrays of ints )) $(DDOC_BLANKLINE ) $(P This is in contrast to C:) $(DDOC_BLANKLINE ) $(CPPCODE int x, *y; // x is an int, y is a pointer to int int x[], y; // x is an array/pointer, y is an int ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 AutoDeclaration, auto-declaration, Implicit Type Inference)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AutoDeclaration): $(GLINK StorageClasses) $(GLINK AutoAssignments) $(D ;) $(DDOC_BLANKLINE ) $(GNAME AutoAssignments): $(GLINK AutoAssignment) $(GSELF AutoAssignments) $(D ,) $(GLINK AutoAssignment) $(DDOC_BLANKLINE ) $(GNAME AutoAssignment): $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT ) $(D =) $(GLINK Initializer) ) $(DDOC_BLANKLINE ) $(P If a declaration starts with a $(I StorageClass) and has a $(I NonVoidInitializer) from which the type can be inferred, the type on the declaration can be omitted. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD static) x = 3; $(D_COMMENT // x is type int )$(D_KEYWORD auto) y = 4u; $(D_COMMENT // y is type uint ) $(D_KEYWORD auto) s = $(D_STRING "Apollo"); $(D_COMMENT // s is type immutable$(LPAREN)char$(RPAREN )[] i.e., string ) $(D_KEYWORD class) C { ... } $(D_KEYWORD auto) c = $(D_KEYWORD new) C(); $(D_COMMENT // c is a handle to an instance of class C )) $(DDOC_BLANKLINE ) $(P The $(I NonVoidInitializer) cannot contain forward references (this restriction may be removed in the future). The implicitly inferred type is statically bound to the declaration at compile time, not run time. ) $(DDOC_BLANKLINE ) $(P An $(GLINK2 expression, ArrayLiteral) is inferred to be a dynamic array type rather than a static array:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) v = [$(D_STRING "resistance"), $(D_STRING "is"), $(D_STRING "useless")]; $(D_COMMENT // type is string[], not string[3] )) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 alias, Alias Declarations)

$(DDOC_BLANKLINE ) $(NOTE New code should use the AliasAssignments form only.) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AliasDeclaration): $(D alias) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 type, TypeSuffixes)$(OPT ) $(GLINK Identifiers) $(D ;) $(D alias) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 function, FuncDeclarator) $(D ;) $(D alias) $(GLINK AliasAssignments) $(D ;) $(DDOC_BLANKLINE ) $(GNAME Identifiers): $(GLINK_LEX Identifier) $(GLINK_LEX Identifier) , $(GSELF Identifiers) $(DDOC_BLANKLINE ) $(GNAME AliasAssignments): $(GLINK AliasAssignment) $(GSELF AliasAssignments) $(D ,) $(GLINK AliasAssignment) $(DDOC_BLANKLINE ) $(GNAME AliasAssignment): $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT ) $(D =) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT ) $(D =) $(GLINK2 expression, FunctionLiteral) $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT ) $(D =) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, Type) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) ) $(DDOC_BLANKLINE ) $(P An $(I AliasDeclaration) creates a symbol name that refers to a type or another symbol. That name can then be used anywhere that the target may appear. The following can be aliased: ) $(UL $(LI $(RELATIVE_LINK2 alias-type, Types) $(UL $(LI $(RELATIVE_LINK2 alias-function, Function Types) (with default arguments)) )) $(LI $(RELATIVE_LINK2 alias-variable, Variables)) $(LI Manifest Constants) $(LI Modules) $(LI Packages) $(LI Functions) $(LI $(RELATIVE_LINK2 alias-overload, Overload Sets)) $(LI $(DDSUBLINK spec/expression, function-literal-alias, Function Literals)) $(LI Templates) $(LI Template Instantiations) $(LI Other Alias Declarations ) )

$(LNAME2 alias-type, Type Aliases)

$(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD alias) myint = abc.Foo.bar; ) $(DDOC_BLANKLINE ) $(P Aliased types are semantically identical to the types they are aliased to. The debugger cannot distinguish between them, and there is no difference as far as function overloading is concerned. For example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD alias) myint = $(D_KEYWORD int); $(D_KEYWORD void) foo($(D_KEYWORD int) x) { ... } $(D_KEYWORD void) foo(myint m) { ... } $(D_COMMENT // error, multiply defined function foo )) $(DDOC_BLANKLINE ) $(P Type aliases can sometimes look indistinguishable from other symbol aliases: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD alias) abc = foo.bar; $(D_COMMENT // is it a type or a symbol? )) $(DDOC_BLANKLINE ) $(BEST_PRACTICE Other than when aliasing simple basic type names, type alias names should be Capitalized.) $(DDOC_BLANKLINE )

$(LNAME2 alias-symbol, Symbol Aliases)

$(DDOC_BLANKLINE ) $(P A symbol can be declared as an $(I alias) of another symbol. For example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD import) planets; $(D_KEYWORD alias) myAlbedo = planets.albedo; ... $(D_KEYWORD int) len = myAlbedo($(D_STRING "Saturn")); $(D_COMMENT // actually calls planets.albedo$(LPAREN)$(RPAREN ) )) $(DDOC_BLANKLINE ) $(P The following alias declarations are valid: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD template) Foo2(T) { $(D_KEYWORD alias) t = T; } $(D_KEYWORD alias) t1 = Foo2!($(D_KEYWORD int)); $(D_KEYWORD alias) t2 = Foo2!($(D_KEYWORD int)).t; $(D_KEYWORD alias) t3 = t1.t; $(D_KEYWORD alias) t4 = t2; t1.t v1; $(D_COMMENT // v1 is type int )t2 v2; $(D_COMMENT // v2 is type int )t3 v3; $(D_COMMENT // v3 is type int )t4 v4; $(D_COMMENT // v4 is type int )) ) $(DDOC_BLANKLINE ) $(P Aliased symbols are useful as a shorthand for a long qualified symbol name, or as a way to redirect references from one symbol to another: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version) (Win32) { $(D_KEYWORD alias) myfoo = win32.foo; } $(D_KEYWORD version) (linux) { $(D_KEYWORD alias) myfoo = linux.bar; } ) $(DDOC_BLANKLINE ) $(P Aliasing can be used to 'import' a symbol from an $(DDSUBLINK spec/module, import-declaration, imported module or package) into the current scope: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD static) $(D_KEYWORD import) string; ... $(D_KEYWORD alias) strlen = string.strlen; ) $(DDOC_BLANKLINE )

$(LNAME2 alias-overload, Aliasing an Overload Set)

$(DDOC_BLANKLINE ) $(P Aliases can also 'import' a set of overloaded functions, that can be overloaded with functions in the current scope: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) B { $(D_KEYWORD int) foo($(D_KEYWORD int) a, $(D_KEYWORD uint) b) { $(D_KEYWORD return) 2; } } $(D_KEYWORD class) C : B { $(D_COMMENT // declaring an overload hides any base class overloads ) $(D_KEYWORD int) foo($(D_KEYWORD int) a) { $(D_KEYWORD return) 3; } $(D_COMMENT // redeclare hidden overload ) $(D_KEYWORD alias) foo = B.foo; } $(D_KEYWORD void) main() { $(D_KEYWORD import) std.stdio; C c = $(D_KEYWORD new) C(); c.foo(1, 2u).writeln; $(D_COMMENT // calls B.foo ) c.foo(1).writeln; $(D_COMMENT // calls C.foo )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 alias-variable, Aliasing Variables)

$(DDOC_BLANKLINE ) $(P Aliases cannot be used for expressions:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD static) $(D_KEYWORD int) i; $(D_KEYWORD static) $(D_KEYWORD int) j; } $(D_KEYWORD alias) a = S.i; $(D_COMMENT // OK, `S.i` is a symbol )$(D_KEYWORD alias) b = S.j; $(D_COMMENT // OK. `S.j` is also a symbol )$(D_COMMENT //alias c = a + b; // illegal, `a + b` is an expression )a = 2; $(D_COMMENT // sets `S.i` to `2` )b = 4; $(D_COMMENT // sets `S.j` to `4` )$(D_KEYWORD assert)(S.i == 2); $(D_KEYWORD assert)(S.j == 4); ) ) $(DDOC_BLANKLINE )

$(LNAME2 alias-function, Aliasing a Function Type)

$(DDOC_BLANKLINE ) $(P $(DDSUBLINK spec/type, functions, Function types) can be aliased:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Fun = $(D_KEYWORD int)(string); $(D_KEYWORD int) fun(string) {$(D_KEYWORD return) 0;} $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(fun) == Fun)); $(D_KEYWORD alias) MemberFun1 = $(D_KEYWORD int)() $(D_KEYWORD const); $(D_KEYWORD alias) MemberFun2 = $(D_KEYWORD const) $(D_KEYWORD int)(); $(D_COMMENT // leading attributes apply to the func, not the return type )$(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(MemberFun1 == MemberFun2)); ) ) $(P Type aliases can be used to call a function with different default arguments, change an argument from required to default or vice versa:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD void) fun($(D_KEYWORD int) v = 6) { writeln($(D_STRING "v: "), v); } $(D_KEYWORD void) main() { fun(); $(D_COMMENT // prints v: 6 ) $(D_KEYWORD alias) Foo = $(D_KEYWORD void) $(D_KEYWORD function)($(D_KEYWORD int)=7); Foo foo = &fun; foo(); $(D_COMMENT // prints v: 7 ) foo(8); $(D_COMMENT // prints v: 8 )} ) ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writefln; $(D_KEYWORD void) main() { fun(4); $(D_COMMENT // prints a: 4, b: 6, c: 7 ) Bar bar = &fun; $(D_COMMENT //bar$(LPAREN)4$(RPAREN ); // compilation error, because the `Bar` alias ) $(D_COMMENT // requires an explicit 2nd argument ) bar(4, 5); $(D_COMMENT // prints a: 4, b: 5, c: 9 ) bar(4, 5, 6); $(D_COMMENT // prints a: 4, b: 5, c: 6 ) Baz baz = &fun; baz(); $(D_COMMENT // prints a: 2, b: 3, c: 4 )} $(D_KEYWORD alias) Bar = $(D_KEYWORD void) $(D_KEYWORD function)($(D_KEYWORD int), $(D_KEYWORD int), $(D_KEYWORD int)=9); $(D_KEYWORD alias) Baz = $(D_KEYWORD void) $(D_KEYWORD function)($(D_KEYWORD int)=2, $(D_KEYWORD int)=3, $(D_KEYWORD int)=4); $(D_KEYWORD void) fun($(D_KEYWORD int) a, $(D_KEYWORD int) b = 6, $(D_KEYWORD int) c = 7) { writefln($(D_STRING "a: %d, b: %d, c: %d"), a, b, c); } ) ) $(DDOC_BLANKLINE )

$(LNAME2 AliasAssign, Alias Assign)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AliasAssign): $(GLINK_LEX Identifier) $(D =) $(GLINK2 type, Type) ) $(DDOC_BLANKLINE ) $(P An $(GLINK AliasDeclaration) can have a new value assigned to it with an $(I AliasAssign):) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD template) Gorgon(T) { $(D_KEYWORD alias) A = $(D_KEYWORD long); A = T; $(D_COMMENT // assign new value to A ) $(D_KEYWORD alias) Gorgon = A; } $(D_KEYWORD pragma)(msg, Gorgon!$(D_KEYWORD int)); $(D_COMMENT // prints int )) ) $(DDOC_BLANKLINE ) $(UL $(LI The $(I AliasAssign) and its corresponding $(I AliasDeclaration) must both be declared in the same $(GLINK2 template, TemplateDeclaration).) $(DDOC_BLANKLINE ) $(LI The corresponding $(I AliasDeclaration) must appear lexically before the $(I AliasAssign).) $(DDOC_BLANKLINE ) $(LI The corresponding $(I AliasDeclaration) may not refer to overloaded symbols.) $(DDOC_BLANKLINE ) $(LI The value of an $(I AliasDeclaration) or left hand side (lvalue) of an $(I AliasAssign) may not be used prior to another $(I AliasAssign) to the same lvalue other than in the right hand side of that $(I AliasAssign).) $(DDOC_BLANKLINE ) ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE $(I AliasAssign) is particularly useful when using an iterative computation rather than a recursive one, as it avoids creating the large number of intermediate templates that the recursive one engenders.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.meta : AliasSeq; $(D_KEYWORD static) $(D_KEYWORD if) (0) $(D_COMMENT // recursive method for comparison ){ $(D_KEYWORD template) Reverse(T...) { $(D_KEYWORD static) $(D_KEYWORD if) (T.length == 0) $(D_KEYWORD alias) Reverse = AliasSeq!(); $(D_KEYWORD else) $(D_KEYWORD alias) Reverse = AliasSeq!(Reverse!(T[1 .. T.length]), T[0]); } } $(D_KEYWORD else) $(D_COMMENT // iterative method minimizes template instantiations ){ $(D_KEYWORD template) Reverse(T...) { $(D_KEYWORD alias) A = AliasSeq!(); $(D_KEYWORD static) $(D_KEYWORD foreach) (t; T) A = AliasSeq!(t, A); $(D_COMMENT // Alias Assign ) $(D_KEYWORD alias) Reverse = A; } } $(D_KEYWORD enum) X = 3; $(D_KEYWORD alias) TK = Reverse!($(D_KEYWORD int), $(D_KEYWORD const) $(D_KEYWORD uint), X); $(D_KEYWORD pragma)(msg, TK); $(D_COMMENT // prints tuple$(LPAREN)3, $(LPAREN)const$(LPAREN)uint$(RPAREN )$(RPAREN ), $(LPAREN)int$(RPAREN )$(RPAREN ) )) ) $(DDOC_BLANKLINE )

$(LNAME2 alias-reassignment, Alias Reassignment)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AliasReassignment): $(GLINK_LEX Identifier) $(D =) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D =) $(GLINK2 expression, FunctionLiteral) $(GLINK_LEX Identifier) $(D =) $(GLINK StorageClasses)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) ) $(DDOC_BLANKLINE ) $(P An alias declaration inside a template can be reassigned a new value.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.meta : AliasSeq; $(D_KEYWORD template) staticMap($(D_KEYWORD alias) F, Args...) { $(D_KEYWORD alias) A = AliasSeq!(); $(D_KEYWORD static) $(D_KEYWORD foreach) (Arg; Args) A = AliasSeq!(A, F!Arg); $(D_COMMENT // alias reassignment ) $(D_KEYWORD alias) staticMap = A; } $(D_KEYWORD enum) size(T) = T.sizeof; $(D_KEYWORD static) $(D_KEYWORD assert)(staticMap!(size, $(D_KEYWORD char), $(D_KEYWORD wchar), $(D_KEYWORD dchar)) == AliasSeq!(1, 2, 4)); ) ) $(DDOC_BLANKLINE ) $(P The $(I Identifier) must resolve to a lexically preceding $(GLINK AliasDeclaration). Both must be members of the same $(GLINK2 template, TemplateDeclaration). ) $(DDOC_BLANKLINE ) $(P The right hand side of the $(I AliasReassignment) replaces the right hand side of the $(I AliasDeclaration). ) $(DDOC_BLANKLINE ) $(P Once the $(I AliasDeclaration) has been referred to in any context other than the right hand side of an $(I AliasReassignment) it can no longer be reassigned. ) $(DDOC_BLANKLINE ) $(RATIONALE Alias reassignment can result in faster compile times and lowered memory consumption, and requires significantly simpler code than the alternative recursive method.) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 extern, Extern Declarations)

$(DDOC_BLANKLINE ) $(P Variable declarations with the storage class $(D extern) are not allocated storage within the module. They must be defined in some other object file with a matching name which is then linked in.) $(DDOC_BLANKLINE ) $(P An $(D extern) declaration can optionally be followed by an $(D extern) $(DDSUBLINK spec/attribute, linkage, linkage attribute). If there is no linkage attribute it defaults to $(D extern(D)):) $(DDOC_BLANKLINE ) $(D_CODE $(D_COMMENT // variable allocated and initialized in this module with C linkage )$(D_KEYWORD extern)(C) $(D_KEYWORD int) foo; $(D_COMMENT // variable allocated outside this module with C linkage )$(D_COMMENT // $(LPAREN)e.g. in a statically linked C library or another module$(RPAREN ) )$(D_KEYWORD extern) $(D_KEYWORD extern)(C) $(D_KEYWORD int) bar; ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE $(OL $(LI The primary usefulness of $(I Extern Declarations) is to connect with global variables declarations and functions in C or C++ files.) )) $(DDOC_BLANKLINE )

$(LNAME2 void_init, Void Initializations)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME VoidInitializer): $(D void) ) $(DDOC_BLANKLINE ) $(P Normally, variables are initialized either with an explicit $(GLINK Initializer) or are set to the default value for the type of the variable. If the $(I Initializer) is $(D void), however, the variable is not initialized. Void initializers for variables with a type that may contain $(DDSUBLINK spec/function, safe-values, unsafe values) (such as types with pointers) are not allowed in @safe code. ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED If a void initialized variable's value is used before it is set, its value is implementation defined. $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) bad() { $(D_KEYWORD int) x = $(D_KEYWORD void); writeln(x); $(D_COMMENT // print implementation defined value )} ) ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR If a void initialized variable's value is used before it is set, and the value is a reference, pointer or an instance of a struct with an invariant, the behavior is undefined. $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) muchWorse() { $(D_KEYWORD char)[] p = $(D_KEYWORD void); writeln(p); $(D_COMMENT // may result in apocalypse )} ) ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE $(OL $(LI Void initializers are useful when a static array is on the stack, but may only be partially used, such as a temporary buffer. Void initializers will potentially speed up the code, but they introduce risk, since one must ensure that array elements are always set before read.) $(LI The same is true for structs.) $(LI Use of void initializers is rarely useful for individual local variables, as a modern optimizer will remove the dead store of its initialization if it is initialized later.) $(LI For hot code paths, it is worth profiling to see if the void initializer actually improves results.) ) ) $(DDOC_BLANKLINE )

$(LNAME2 global_static_init, Global and Static Initializers)

$(DDOC_BLANKLINE ) $(P The $(GLINK Initializer) for a global or static variable must be evaluatable at compile time. Runtime initialization is done with static constructors. ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED $(OL $(LI Whether some pointers can be initialized with the addresses of other functions or data.) )) $(DDOC_BLANKLINE )

$(LNAME2 typequal_vs_storageclass, Type Qualifiers vs. Storage Classes)

$(DDOC_BLANKLINE ) $(P $(DDLINK spec/const3, Type Qualifiers, Type qualifers) and $(RELATIVE_LINK2 storage-classes, storage classes) are distinct concepts.) $(DDOC_BLANKLINE ) $(P A $(I type qualifier) creates a derived type from an existing base type, and the resulting type may be used to create multiple instances of that type.) $(DDOC_BLANKLINE ) $(P For example, the $(D immutable) type qualifier can be used to create variables of immutable type, such as:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD immutable)($(D_KEYWORD int)) x; $(D_COMMENT // typeof$(LPAREN)x$(RPAREN ) == immutable$(LPAREN)int$(RPAREN ) )$(D_KEYWORD immutable)($(D_KEYWORD int))[] y; $(D_COMMENT // typeof$(LPAREN)y$(RPAREN ) == immutable$(LPAREN)int$(RPAREN )[] ) $(D_COMMENT // typeof$(LPAREN)y[0]$(RPAREN ) == immutable$(LPAREN)int$(RPAREN ) ) $(D_COMMENT // Type constructors create new types that can be aliased: )$(D_KEYWORD alias) ImmutableInt = $(D_KEYWORD immutable)($(D_KEYWORD int)); ImmutableInt z; $(D_COMMENT // typeof$(LPAREN)z$(RPAREN ) == immutable$(LPAREN)int$(RPAREN ) )) $(DDOC_BLANKLINE ) $(P A $(I storage class), on the other hand, does not create a new type, but describes only the kind of storage used by the variable or function being declared. For example, a member function can be declared with the $(D const) storage class to indicate that it does not modify its implicit $(D this) argument:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD int) x; $(D_KEYWORD int) method() $(D_KEYWORD const) { $(D_COMMENT //x++; // Error: this method is const and cannot modify this.x ) $(D_KEYWORD return) x; $(D_COMMENT // OK: we can still read this.x ) } } ) ) $(P Although some keywords can be $(RELATIVE_LINK2 methods-returning-qualified, used as both) a type qualifier and a storage class, there are some storage classes that cannot be used to construct new types, such as $(D ref).) $(DDOC_BLANKLINE )

$(LNAME2 ref-storage, ref Storage Class)

$(DDOC_BLANKLINE ) $(P A parameter $(DDSUBLINK spec/function, ref-params, declared with ref) is passed by reference:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) func($(D_KEYWORD ref) $(D_KEYWORD int) i) { i++; $(D_COMMENT // modifications to i will be visible in the caller )} $(D_KEYWORD void) main() { $(D_KEYWORD auto) x = 1; func(x); $(D_KEYWORD assert)(x == 2); $(D_COMMENT // However, ref is not a type qualifier, so the following is illegal: ) $(D_COMMENT //ref$(LPAREN)int$(RPAREN ) y; // Error: ref is not a type qualifier. )} ) ) $(P Functions can also be $(DDSUBLINK spec/function, ref-functions, declared as ref), meaning their return value is passed by reference:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD ref) $(D_KEYWORD int) func2() { $(D_KEYWORD static) $(D_KEYWORD int) y = 0; $(D_KEYWORD return) y; } $(D_KEYWORD void) main() { func2() = 2; $(D_COMMENT // The return value of func2$(LPAREN)$(RPAREN ) can be modified. ) $(D_KEYWORD assert)(func2() == 2); $(D_COMMENT // However, the reference returned by func2$(LPAREN)$(RPAREN ) does not propagate to ) $(D_COMMENT // variables, because the 'ref' only applies to the return value itself, ) $(D_COMMENT // not to any subsequent variable created from it: ) $(D_KEYWORD auto) x = func2(); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(x) == $(D_KEYWORD int))); $(D_COMMENT // N.B.: *not* ref$(LPAREN)int$(RPAREN ); ) $(D_COMMENT // there is no such type as ref$(LPAREN)int$(RPAREN ). ) x++; $(D_KEYWORD assert)(x == 3); $(D_KEYWORD assert)(func2() == 2); $(D_COMMENT // x is not a reference to what func2$(LPAREN)$(RPAREN ) returned; it ) $(D_COMMENT // does not inherit the ref storage class from func2$(LPAREN)$(RPAREN ). )} ) )

$(LNAME2 methods-returning-qualified, Methods Returning a Qualified Type)

$(DDOC_BLANKLINE ) $(P Some keywords, such as $(D const), can be used both as a type qualifier and a storage class. The distinction is determined by the syntax where it appears.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_COMMENT /* Is const here a type qualifier or a storage class? * Is the return value const$(LPAREN)int$(RPAREN ), or is this a const function that returns * $(LPAREN)mutable$(RPAREN ) int? */) $(D_KEYWORD const) $(D_KEYWORD int)* func() $(D_COMMENT // a const function ) { $(D_COMMENT //++p; // error, this.p is const ) $(D_COMMENT //return p; // error, cannot convert const$(LPAREN)int$(RPAREN )* to int* ) $(D_KEYWORD return) $(D_KEYWORD null); } $(D_KEYWORD const)($(D_KEYWORD int))* func() $(D_COMMENT // a function returning a pointer to a const int ) { ++p; $(D_COMMENT // ok, this.p is mutable ) $(D_KEYWORD return) p; $(D_COMMENT // ok, int* can be implicitly converted to const$(LPAREN)int$(RPAREN )* ) } $(D_KEYWORD int)* p; } ) ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE To avoid confusion, the type qualifier syntax with parentheses should be used for return types, and function storage classes should be written on the right-hand side of the declaration instead of the left-hand side where it may be visually confused with the return type: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD struct) S { $(D_COMMENT // Now it is clear that the 'const' here applies to the return type: ) $(D_KEYWORD const)($(D_KEYWORD int)) func1() { $(D_KEYWORD return) 1; } $(D_COMMENT // And it is clear that the 'const' here applies to the function: ) $(D_KEYWORD int) func2() $(D_KEYWORD const) { $(D_KEYWORD return) 1; } } ) ) $(DDOC_BLANKLINE ) $(SPEC_SUBNAV_PREV_NEXT module, Modules, type, Types) ) $(DDOC_BLANKLINE ) )