Ddoc $(SPEC_S Declarations, $(GRAMMAR $(GNAME Declaration): $(V1 $(B typedef) $(I Decl) ) $(B alias) $(I Decl) $(I Decl) $(GNAME Decl): $(GLINK StorageClasses) $(I Decl) $(GLINK BasicType) $(GLINK Declarators) $(B ;) $(GLINK BasicType) $(GLINK Declarator) $(LINK2 function.html#FunctionBody, $(I FunctionBody)) $(GLINK AutoDeclaration) $(GNAME Declarators): $(I DeclaratorInitializer) $(I DeclaratorInitializer) $(B ,) $(GLINK DeclaratorIdentifierList) $(GNAME DeclaratorInitializer): $(GLINK Declarator) $(GLINK Declarator) $(B =) $(GLINK Initializer) $(GNAME DeclaratorIdentifierList): $(GLINK DeclaratorIdentifier) $(GLINK DeclaratorIdentifier) $(B ,) $(I DeclaratorIdentifierList) $(GNAME DeclaratorIdentifier): $(I Identifier) $(I Identifier) $(B =) $(GLINK Initializer) $(GNAME BasicType): $(GLINK BasicTypeX) $(B .)$(GLINK IdentifierList) $(GLINK IdentifierList) $(GLINK Typeof) $(GLINK Typeof) $(B .) $(GLINK IdentifierList) $(V2 $(B const$(LPAREN)) $(GLINK type) $(B $(RPAREN)) $(B immutable$(LPAREN)) $(GLINK type) $(B $(RPAREN)) $(B shared$(LPAREN)) $(GLINK type) $(B $(RPAREN)) $(B inout$(LPAREN)) $(GLINK type) $(B $(RPAREN)) ) $(GNAME BasicTypeX): $(B bool) $(B byte) $(B ubyte) $(B short) $(B ushort) $(B int) $(B uint) $(B long) $(B ulong) $(B char) $(B wchar) $(B dchar) $(B float) $(B double) $(B real) $(B ifloat) $(B idouble) $(B ireal) $(B cfloat) $(B cdouble) $(B creal) $(B void) $(GNAME BasicType2): $(B *) $(B [ ]) $(B [) $(VEXPRESSION) $(B ]) $(B [) $(VEXPRESSION) .. $(VEXPRESSION) $(B ]) $(B [) $(GLINK Type) $(B ]) $(B delegate) $(GLINK Parameters) $(V2 $(GLINK FunctionAttributes)$(OPT)) $(B function) $(GLINK Parameters) $(V2 $(GLINK FunctionAttributes)$(OPT)) $(GNAME Declarator): $(GLINK BasicType2)$(OPT) $(B $(LPAREN)) $(I Declarator) $(B $(RPAREN)) $(GLINK DeclaratorSuffixes)$(OPT) $(GLINK BasicType2)$(OPT) $(I Identifier) $(GLINK DeclaratorSuffixes)$(OPT) $(GNAME DeclaratorSuffixes): $(GLINK DeclaratorSuffix) $(GLINK DeclaratorSuffix) $(I DeclaratorSuffixes) $(GNAME DeclaratorSuffix): $(B [ ]) $(B [) $(VEXPRESSION) $(B ]) $(B [) $(GLINK Type) $(B ]) $(GLINK2 template, TemplateParameterList)$(OPT) $(GLINK Parameters) $(V2 $(GLINK MemberFunctionAttributes)$(OPT) $(GLINK2 template, Constraint)$(OPT)) $(GNAME IdentifierList): $(I Identifier) $(I Identifier) $(B .) $(I IdentifierList) $(GLINK2 template, TemplateInstance) $(GLINK2 template, TemplateInstance) $(B .) $(I IdentifierList) $(GNAME StorageClasses): $(GLINK StorageClass) $(GLINK StorageClass) $(I StorageClasses) $(GNAME StorageClass): $(B abstract) $(B auto) $(B const) $(B deprecated) $(B extern) $(B final) $(V2 $(B immutable) $(B inout) $(B shared) $(B nothrow) $(B override) $(B pure) $(B __gshared) $(GLINK Property) ) $(B scope) $(B static) $(B synchronized) $(GNAME Property): $(B @) $(I Identifier) $(GNAME Type): $(GLINK BasicType) $(GLINK BasicType) $(GLINK Declarator2) $(GNAME Declarator2): $(GLINK BasicType2)$(OPT) $(GLINK DeclaratorSuffixes)$(OPT) $(GLINK BasicType2)$(OPT) $(B $(LPAREN)) $(I Declarator2) $(B $(RPAREN)) $(GLINK DeclaratorSuffixes)$(OPT) $(GNAME Parameters): $(B $(LPAREN)) $(GLINK ParameterList) $(B $(RPAREN)) $(B ( )) $(GNAME ParameterList): $(GLINK Parameter) $(GLINK Parameter) $(B ,) $(I ParameterList) $(B ...) $(GNAME Parameter): $(I InOut)$(OPT) $(GLINK BasicType) $(GLINK Declarator) $(I InOut)$(OPT) $(GLINK BasicType) $(GLINK Declarator) $(B ...) $(I InOut)$(OPT) $(GLINK BasicType) $(GLINK Declarator) = $(GLINK DefaultInitializerExpression) $(I InOut)$(OPT) $(GLINK Type) $(I InOut)$(OPT) $(GLINK Type) $(B ...) $(GNAME InOut): $(I InOutX) $(I InOut InOutX) $(GNAME InOutX): $(B auto) $(B const) $(B final) $(V2 $(B immutable) ) $(B in) $(B inout) $(B lazy) $(B out) $(B ref) $(B scope) $(B shared) $(V2 $(GNAME FunctionAttributes): $(GLINK FunctionAttribute) $(GLINK FunctionAttribute) $(I FunctionAttributes) $(GNAME FunctionAttribute): $(B nothrow) $(B pure) $(GLINK Property) ) $(GNAME MemberFunctionAttributes): $(GLINK MemberFunctionAttribute) $(GLINK MemberFunctionAttribute) $(I MemberFunctionAttributes) $(GNAME MemberFunctionAttribute): $(B const) $(B immutable) $(B inout) $(B shared) $(GLINK FunctionAttribute) $(GNAME DefaultInitializerExpression): $(ASSIGNEXPRESSION) $(V2 $(B __FILE__) $(B __LINE__)) $(GNAME Initializer): $(GLINK VoidInitializer) $(GLINK NonVoidInitializer) $(GNAME NonVoidInitializer): $(ASSIGNEXPRESSION) $(GLINK ArrayInitializer) $(GLINK StructInitializer) $(GNAME ArrayInitializer): $(B [ ]) $(B [) $(GLINK ArrayMemberInitializations) $(B ]) $(GNAME ArrayMemberInitializations): $(GLINK ArrayMemberInitialization) $(GLINK ArrayMemberInitialization) $(B ,) $(GLINK ArrayMemberInitialization) $(B ,) $(I ArrayMemberInitializations) $(GNAME ArrayMemberInitialization): $(GLINK NonVoidInitializer) $(ASSIGNEXPRESSION) $(B :) $(GLINK NonVoidInitializer) $(GNAME StructInitializer): $(B { }) $(B {) $(GLINK StructMemberInitializers) $(B }) $(GNAME StructMemberInitializers): $(GLINK StructMemberInitializer) $(GLINK StructMemberInitializer) $(B ,) $(GLINK StructMemberInitializer) $(B ,) $(I StructMemberInitializers) $(GNAME StructMemberInitializer): $(GLINK NonVoidInitializer) $(I Identifier) $(B :) $(GLINK NonVoidInitializer) )

Declaration Syntax

$(P Declaration syntax generally reads right to left:) -------------------- int x; // x is an int int* x; // x is a pointer to int int** x; // x is a pointer to a pointer to int int[] x; // x is an array of ints int*[] x; // x is an array of pointers to ints int[]* x; // x is a pointer to an array of ints -------------------- $(P Arrays read right to left as well:) -------------------- int[3] x; // x is an array of 3 ints int[3][5] x; // x is an array of 5 arrays of 3 ints int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints -------------------- $(P Pointers to functions are declared using the $(B function) keyword: ) -------------------- int $(B function)(char) x; // x is a pointer to a function taking a char argument // and returning an int int $(B function)(char)[] x; // x is an array of pointers to functions // taking a char argument and returning an int -------------------- $(P $(V1 C-style array, function pointer and pointer to array declarations are possible as an alternative:) $(V2 C-style array, function pointer and pointer to array declarations are deprecated:) ) -------------------- int x[3]; // x is an array of 3 ints int x[3][5]; // x is an array of 3 arrays of 5 ints int (*x[5])[3]; // x is an array of 5 pointers to arrays of 3 ints int (*x)(char); // x is a pointer to a function taking a char argument // and returning an int int (*[] x)(char); // x is an array of pointers to functions // taking a char argument and returning an int -------------------- $(P In a declaration declaring multiple symbols, all the declarations must be of the same type: ) -------------------- int x,y; // x and y are ints int* x,y; // x and y are pointers to ints int x,*y; // error, multiple types int[] x,y; // x and y are arrays of ints int x[],y; // error, multiple types --------------------

Implicit Type Inference

$(GRAMMAR $(GNAME AutoDeclaration): $(GLINK StorageClasses) $(I AutoDeclarationX) $(B ;) $(GNAME AutoDeclarationX): $(I Identifier) $(B =) $(GLINK Initializer) $(I AutoDeclarationX) $(B ,) $(I Identifier) $(B =) $(GLINK Initializer) ) $(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. ) ---------- static x = 3; // x is type int auto y = 4u; // y is type uint $(V1 auto s = "string"; // s is type char[6]) $(V2 auto s = "string"; // s is type immutable(char)[]) class C { ... } auto c = new C(); // c is a handle to an instance of class C ---------- $(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. ) $(V2 $(P An $(LINK2 expression.html#ArrayLiteral, $(I ArrayLiteral)) is inferred to be a dynamic array type rather than a static array:) --- auto v = ["hello", "world"]; // type is string[], not string[2] --- ) $(V1

Type Defining

$(P Strong types can be introduced with the typedef. Strong types are semantically a distinct type to the type checking system, for function overloading, and for the debugger. ) -------------------- typedef int myint; void foo(int x) { . } void foo(myint m) { . } . myint b; foo(b); // calls foo(myint) -------------------- Typedefs can specify a default initializer different from the default initializer of the underlying type: -------------------- typedef int myint = 7; myint m; // initialized to 7 -------------------- )

Type Aliasing

$(P It's sometimes convenient to use an alias for a type, such as a shorthand for typing out a long, complex type like a pointer to a function. In D, this is done with the alias declaration: ) -------------------- $(B alias) abc.Foo.bar myint; -------------------- $(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: ) -------------------- $(B alias) int myint; void foo(int x) { . } void foo(myint m) { . } // error, multiply defined function foo -------------------- $(V1 $(P Type aliases are equivalent to the C typedef. ) )

Alias Declarations

$(P A symbol can be declared as an $(I alias) of another symbol. For example: ) -------------------- import string; $(B alias) string.strlen mylen; ... int len = mylen("hello"); // actually calls string.strlen() -------------------- $(P The following alias declarations are valid: ) -------------------- template Foo2(T) { $(B alias) T t; } $(B alias) Foo2!(int) t1; $(B alias) Foo2!(int).t t2; $(B alias) t1.t t3; $(B alias) t2 t4; t1.t v1; // v1 is type int t2 v2; // v2 is type int t3 v3; // v3 is type int t4 v4; // v4 is type int -------------------- $(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: ) -------------------- version (Win32) { $(B alias) win32.foo myfoo; } version (linux) { $(B alias) linux.bar myfoo; } -------------------- $(P Aliasing can be used to $(SINGLEQUOTE import) a symbol from an import into the current scope: ) -------------------- $(B alias) string.strlen strlen; -------------------- $(P Aliases can also $(SINGLEQUOTE import) a set of overloaded functions, that can be overloaded with functions in the current scope: ) -------------------- class A { int foo(int a) { return 1; } } class B : A { int foo( int a, uint b ) { return 2; } } class C : B { int foo( int a ) { return 3; } $(B alias) B.foo foo; } class D : C { } void test() { D b = new D(); int i; i = b.foo(1, 2u); // calls B.foo i = b.foo(1); // calls C.foo } -------------------- $(P $(B Note:) Type aliases can sometimes look indistinguishable from alias declarations: ) -------------------- $(B alias) foo.bar abc; // is it a type or a symbol? -------------------- $(P The distinction is made in the semantic analysis pass. ) $(P Aliases cannot be used for expressions:) ----------- struct S { static int i; } S s; alias s.i a; // illegal, s.i is an expression alias S.i b; // ok b = 4; // sets S.i to 4 -----------

Extern Declarations

Variable declarations with the storage class $(B 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. The primary usefulness of this is to connect with global variable declarations in C files.

typeof

$(GRAMMAR $(GNAME Typeof): $(B typeof $(LPAREN)) $(EXPRESSION) $(B $(RPAREN)) $(B typeof $(LPAREN)) $(B return) $(B $(RPAREN)) ) $(P $(I Typeof) is a way to specify a type based on the type of an expression. For example: ) -------------------- void func(int i) { $(B typeof)(i) j; // j is of type int $(B typeof)(3 + 6.0) x; // x is of type double $(B typeof)(1)* p; // p is of type pointer to int int[$(B typeof)(p)] a; // a is of type int[int*] writefln("%d", $(B typeof)('c').sizeof); // prints 1 double c = cast($(B typeof)(1.0))j; // cast j to double } -------------------- $(P $(I Expression) is not evaluated, just the type of it is generated: ) -------------------- void func() { int i = 1; $(B typeof)(++i) j; // j is declared to be an int, i is not incremented writefln("%d", i); // prints 1 } -------------------- $(P There are $(V1 two) $(V2 three) special cases: $(OL $(LI $(B typeof(this)) will generate the type of what $(B this) would be in a non-static member function, even if not in a member function. ) $(LI Analogously, $(B typeof(super)) will generate the type of what $(B super) would be in a non-static member function. ) $(V2 $(LI $(B typeof(return)) will, when inside a function scope, give the return type of that function. ) ) ) ) -------------------- class A { } class B : A { $(B typeof(this)) x; // x is declared to be a B $(B typeof(super)) y; // y is declared to be an A } struct C { $(B typeof(this)) z; // z is declared to be a C* $(B typeof(super)) q; // error, no super struct for C } $(B typeof(this)) r; // error, no enclosing struct or class -------------------- $(P Where $(I Typeof) is most useful is in writing generic template code. )

Void Initializations

$(GRAMMAR $(GNAME VoidInitializer): $(B void) ) Normally, variables are initialized either with an explicit $(I Initializer) or are set to the default value for the type of the variable. If the $(I Initializer) is $(B void), however, the variable is not initialized. If its value is used before it is set, undefined program behavior will result. ------------------------- void foo() { int x = void; writefln(x); // will print garbage } ------------------------- Therefore, one should only use $(B void) initializers as a last resort when optimizing critical code. ) Macros: TITLE=Declarations WIKI=Declaration OPT=opt ASSIGNEXPRESSION=$(LINK2 expression.html#AssignExpression, $(I AssignExpression)) EXPRESSION=$(LINK2 expression.html#Expression, $(I Expression)) VEXPRESSION=$(V1 $(EXPRESSION))$(V2 $(ASSIGNEXPRESSION)) FOO=