D Programming Language 2.0

- Comments
- D
- Search
- Downloads
- Home

Last update Tue Jun 17 20:13:35 2008

# Declarations

    Declaration:
            typedef Decl
            alias Decl
            Decl

    Decl:
            StorageClasses Decl
            BasicType Declarators ;
            BasicType Declarator FunctionBody
    	AutoDeclaration

    Declarators:
            DeclaratorInitializer
            DeclaratorInitializer , DeclaratorIdentifierList

    DeclaratorInitializer:
            Declarator
            Declarator = Initializer

    DeclaratorIdentifierList:
            DeclaratorIdentifier
            DeclaratorIdentifier , DeclaratorIdentifierList

    DeclaratorIdentifier:
            Identifier
            Identifier = Initializer

    BasicType:
            bool
            byte
            ubyte
            short
            ushort
            int
            uint
            long
            ulong
            char
            wchar
            dchar
            float
            double
            real
            ifloat
            idouble
            ireal
            cfloat
            cdouble
            creal
            void
            .IdentifierList
            IdentifierList
            Typeof
            Typeof . IdentifierList

    BasicType2:
            *
            [ ]
            [ Expression ]
            [ Type ]
            delegate Parameters FunctionAttributesopt
            function Parameters FunctionAttributesopt

    Declarator:
            BasicType2 Declarator
            Identifier
            () Declarator
            Identifier DeclaratorSuffixes
            () Declarator  DeclaratorSuffixes

    DeclaratorSuffixes:
            DeclaratorSuffix
            DeclaratorSuffix DeclaratorSuffixes

    DeclaratorSuffix:
            [ ]
            [ Expression ]
            [ Type ]
    	Parameters FunctionAttributesopt

    IdentifierList:
            Identifier
            Identifier . IdentifierList
            TemplateInstance
            TemplateInstance . IdentifierList

    StorageClasses:
    	StorageClass
    	StorageClass StorageClasses

    StorageClass:
            abstract
            auto
            const
            deprecated
            extern
            final
            invariant
    	nothrow
            override
    	pure
            scope
            static
            synchronized

    Type:
            BasicType
            BasicType Declarator2

    Declarator2:
            BasicType2 Declarator2
            ( Declarator2 )
            ( Declarator2 ) DeclaratorSuffixes

    Parameters:
    	( ParameterList )
    	( )

    ParameterList:
            Parameter
            Parameter , ParameterList
            Parameter ...
            ...

    Parameter:
            Declarator
            Declarator = DefaultInitializerExpression
            InOut Declarator
            InOut Declarator = DefaultInitializerExpression

    InOut:
            in
            out
            ref
            lazy

    FunctionAttributes:
    	FunctionAttribute
    	FunctionAttribute FunctionAttributes

    FunctionAttribute:
    	pure
    	nothrow

    DefaultInitializerExpression:
    	AssignExpression
    	__FILE__
    	__LINE__

    Initializer:
            VoidInitializer
    	NonVoidInitializer

    NonVoidInitializer:
            AssignExpression
            ArrayInitializer
            StructInitializer

    ArrayInitializer:
    	[ ]
    	[ ArrayMemberInitializations ]

    ArrayMemberInitializations:
    	ArrayMemberInitialization
    	ArrayMemberInitialization ,
    	ArrayMemberInitialization , ArrayMemberInitializations

    ArrayMemberInitialization:
    	NonVoidInitializer
    	AssignExpression : NonVoidInitializer

    StructInitializer:
    	{  }
    	{ StructMemberInitializers }

    StructMemberInitializers:
    	StructMemberInitializer
    	StructMemberInitializer ,
    	StructMemberInitializer , StructMemberInitializers

    StructMemberInitializer:
    	NonVoidInitializer
    	Identifier : NonVoidInitializer

### Declaration Syntax

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

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

Pointers to functions are declared using the function keyword:

    int function(char) x;   // x is a pointer to a function taking a char argument
    			// and returning an int
    int function(char)[] x; // x is an array of pointers to functions
    			// taking a char argument and returning an int

C-style array declarations may be used as an alternative:

    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

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

    AutoDeclaration:
    	StorageClasses Identifier = AssignExpression ;

If a declaration starts with a StorageClass and has a 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
    auto s = "string"; // s is type char[6]

    class C { ... }

    auto c = new C();  // c is a handle to an instance of class C

The 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.

### Type Defining

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

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:

    alias abc.Foo.bar myint;

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:

    alias int myint;

    void foo(int x) { . }
    void foo(myint m) { . }	// error, multiply defined function foo

Type aliases are equivalent to the C typedef.

### Alias Declarations

A symbol can be declared as an alias of another symbol. For example:

    import string;

    alias string.strlen mylen;
     ...
    int len = mylen("hello");	// actually calls string.strlen()

The following alias declarations are valid:

    template Foo2(T) { alias T t; }
    alias Foo2!(int) t1;
    alias Foo2!(int).t t2;
    alias t1.t t3;
    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

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)
    {
        alias win32.foo myfoo;
    }
    version (linux)
    {
        alias linux.bar myfoo;
    }

Aliasing can be used to 'import' a symbol from an import into the current scope:

    alias string.strlen strlen;

Aliases can also '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; }
        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
    }

Note: Type aliases can sometimes look indistinguishable from alias declarations:

    alias foo.bar abc;	// is it a type or a symbol?

The distinction is made in the semantic analysis pass.

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 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

    Typeof:
            typeof ( Expression )
            typeof ( return )

Typeof is a way to specify a type based on the type of an expression. For example:

    void func(int i)
    {
        typeof(i) j;	// j is of type int
        typeof(3 + 6.0) x;	// x is of type double
        typeof(1)* p;	// p is of type pointer to int
        int[typeof(p)] a;	// a is of type int[int*]

        writefln("%d", typeof('c').sizeof);	// prints 1
        double c = cast(typeof(1.0))j;	// cast j to double
    }

Expression is not evaluated, just the type of it is generated:

    void func()
    {   int i = 1;
        typeof(++i) j;	// j is declared to be an int, i is not incremented
        writefln("%d", i);	// prints 1
    }

There are three special cases:

1. typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function.
2. Analogously, typeof(super) will generate the type of what super would be in a non-static member function.
3. typeof(return) will, when inside a function scope, give the return type of that function.

    class A { }

    class B : A
    {
        typeof(this) x;	// x is declared to be a B
        typeof(super) y;	// y is declared to be an A
    }

    struct C
    {
        typeof(this) z;	// z is declared to be a C*
        typeof(super) q;	// error, no super struct for C
    }

    typeof(this) r;		// error, no enclosing struct or class

Where Typeof is most useful is in writing generic template code.

### Void Initializations

    VoidInitializer:
    	void

Normally, variables are initialized either with an explicit Initializer or are set to the default value for the type of the variable. If the Initializer is 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 void initializers as a last resort when optimizing critical code.
Copyright © 1999-2008 by Digital Mars, All Rights Reserved | Page generated by Ddoc. | Comments