www.digitalmars.com [Home] [Search] [D]
Last modified Feb 4, 2002.

Declarations

Declaration Syntax

Declaration syntax generally reads left to right:
	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, when lexically next to each other, read right to left:
	int[3] x;	// x is an array of 3 ints
	int[3][5] x;	// x is an array of 3 arrays of 5 ints
	int[3]*[5] x;	// x is an array of 5 pointers to arrays of 3 ints
	
Pointers to functions are declared as subdeclarations:
	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
	
C-style array declarations, where the [] appear to the right of the identifier, 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
	
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 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.

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)
	

Structs, Unions

They work like they do in C, with the following exceptions: Structs and unions are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type. External types can be defined by the operating system API, or by a file format. Object oriented features are provided with the class data type.

[Note: perhaps we should do away with unions entirely, or at least unions that contain pointers.]

Static Initialization of Structs

Static struct members are by default initialized to 0, and floating point values to NAN. If a static initializer is supplied, the members are initialized by the member name, colon, expression syntax. The members may be initialized in any order.
	struct X { int a; int b; int c; int d = 7;}
	static X x = { a:1, b:2};	// c is set to 0, d to 7
	static X z = { c:4, b:5, a:2 , d:5};	  // z.a = 2, z.b = 5, z.c = 4, d = 5
	

Static Initialization of Unions

Unions are initialized explicitly.
	union U { int a; double b; }
	static U u = { b : 5.0 };		// u.b = 5.0
	
Other members of the union that overlay the initializer, but occupy more storage, have the extra storage initialized to zero.

Enums

	enum identifier { EnumMembers }
	
Enums, of course, replace the usual use of #define macros to define constants. Enums can be either anonymous, in which case they simply define integral constants, or they can be named, in which case they introduce a new type.
	enum { A, B, C };
	
Defines the constants A=0, B=1, C=2 in a manner equivalent to:
	const int A = 0;
	const int B = 1;
	const int C = 2;
	
Whereas:
	enum X { A, B, C };
	
Define a new type X which has values X.A=0, X.B=1, X.C=2

Named enum members can be implicitly cast to integral types, but integral types cannot be implicitly cast to an enum type.

Enums must have at least one member.

Enum Properties

	.min			Smallest value of enum
	.max			Largest value of enum
	.size			Size of storage for an enumerated value

	For example:

	X.min			is X.A
	X.max			is X.C
	X.size			is same as int.size

Initialization of Enums

In the absense of an explicit initializer, an enum variable or member is initialized to the first enum value.

Version Specifications

	VersionSpecification
	    version = Identifier ;
	    version = Integer ;
	
Version specifications do not declare any symbols, but instead set a version in the same manner that the -version does on the command line. The version specification is used for conditional compilation with version attributes and version statements.

The version specification makes it straightforward to group a set of features under one major version, for example:

	version (ProfessionalEdition)
	{
	    version = FeatureA;
	    version = FeatureB;
	    version = FeatureC;
	}
	version (HomeEdition)
	{
	    version = FeatureA;
	}
	...
	version (FeatureB)
	{
	    ... implement Feature B ...
	}
	

Copyright (c) 1999-2002 by Digital Mars, All Rights Reserved