www.digitalmars.com [Home] [Search] [D]
Last modified Aug 29, 2004.

Declarations

	Declaration:
		typedef Decl
		alias Decl
		Decl

	Decl:
		StorageClass Decl
		BasicType Declarators ;
		BasicType Declarator FunctionBody

	Declarators:
		DeclaratorInitializer
		DeclaratorInitializer , DeclaratorIdentifierList

	DeclaratorInitializer:
		Declarator
		Declarator = Initializer

	DeclaratorIdentifierList:
		DeclaratorIdentifier
		DeclaratorIdentifier , DeclaratorIdentifierList

	DeclaratorIdentifier:
		Identifier
		Identifier = Initializer

	BasicType:
		bit
		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 ( ParameterList )
		function ( ParameterList )

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

	DeclaratorSuffixes:
		DeclaratorSuffix
		DeclaratorSuffix DeclaratorSuffixes

	DeclaratorSuffix:
		[ ]
		[ Expression ]
		[ Type ]
		( ParameterList )

	IdentifierList
		Identifier
		Identifier . IdentifierList
		TemplateInstance
		TemplateInstance . IdentifierList

	Typeof
		typeof ( Expression )

	StorageClass:
		abstract
		auto
		const
		deprecated
		final
		override
		static
		synchronized

	Type:
		BasicType
		BasicType Declarator2

	Declarator2:
		BasicType2 Declarator2
		( Declarator2 )
		( Declarator2 ) DeclaratorSuffixes

	ParameterList:
		Parameter
		Paremeter , ParameterList
		...

	Parameter:
		Declarator
		Declarator = AssignExpression
		InOut Declarator
		InOut Declarator = AssignExpression

	InOut:
		in
		out
		inout

	

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 left to right:
	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 declarations, 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
	

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.

typeof

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

	    printf("%d\n", typeof('c').size);	// 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
	    printf("%d\n", i);	// prints 1
	}
	
There are two special cases: typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function. Analogously, typeof(super) will generate the type of what super would be in a non-static member 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.

Feedback and Comments

Add feedback and comments regarding this page.
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved