diff -uNr dmd-0.123/dmd/html/d/abi.html dmd-0.124/dmd/html/d/abi.html --- dmd-0.123/dmd/html/d/abi.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/abi.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,181 +1,213 @@ - - -D Application Binary Interface - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update Jul 16, 2004 -
- -

D Application Binary Interface

- - A D implementation that conforms to the D ABI (Application Binary Interface) - will be able to generate libraries, DLL's, etc., that can interoperate with - D binaries built by other implementations. -

- - Most of this specification remains TBD (To Be Defined). - -

C ABI

- - The C ABI referred to in this specification means the C Application - Binary Interface of the target system. - C and D code should be freely linkable together, in particular, D - code shall have access to the entire C ABI runtime library. - -

Basic Types

- - TBD - -

Structs

- - Conforms to the target's C ABI struct layout. - -

Classes

- - An object consists of: - -
-	offset	contents
-	------  --------
-	0:	pointer to vtable
-	4:	monitor
-	8...	non-static members
-	
- - The vtable consists of: - -
-	0:	pointer to instance of ClassInfo
-	4...	pointers to virtual member functions
-	
- - The class definition: - -
-	class XXXX
-	{
-	    ....
-	};
-	
- - Generates the following: - - - -

Interfaces

- - TBD - -

Arrays

- - A dynamic array consists of: - -
-	0:	array dimension
-	4:	pointer to array data
-	
- - A dynamic array is declared as: - -
-	type array[];
-	
- - whereas a static array is declared as: - -
-	type array[dimension];
-	
- - Thus, a static array always has the dimension statically available as part of the type, and - so it is implemented like in C. Static array's and Dynamic arrays can be easily converted back - and forth to each other. - - -

Associative Arrays

- - TBD - -

Reference Types

- - D has reference types, but they are implicit. For example, classes are always - referred to by reference; this means that class instances can never reside on the stack - or be passed as function parameters. -

- - When passing a static array to a function, the result, although declared as a static array, will - actually be a reference to a static array. For example: - -

-	int abc[3];
-	
- - Passing abc to functions results in these implicit conversions: - -
-	void func(int array[3]);	// actually 
-	void func(int *p);		// abc[3] is converted to a pointer to the first element
-	void func(int array[]);	// abc[3] is converted to a dynamic array
-	
- - -

Name Mangling

- - TBD - -

Function Calling Conventions

- - TBD - -

Exception Handling

- -

Windows

- - Conforms to the Microsoft Windows Structured Exception Handling - conventions. - TBD - -

Linux

- - Uses static address range/handler tables. - TBD - -

Garbage Collection

- - TBD - -

Runtime Helper Functions

- - TBD - -

Module Initialization and Termination

- - TBD - -

Unit Testing

- - TBD - -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Application Binary Interface + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

D Application Binary Interface

+ + A D implementation that conforms to the D ABI (Application Binary Interface) + will be able to generate libraries, DLL's, etc., that can interoperate with + D binaries built by other implementations. +

+ + Most of this specification remains TBD (To Be Defined). + +

C ABI

+ + The C ABI referred to in this specification means the C Application + Binary Interface of the target system. + C and D code should be freely linkable together, in particular, D + code shall have access to the entire C ABI runtime library. + +

Basic Types

+ + TBD + +

Structs

+ + Conforms to the target's C ABI struct layout. + +

Classes

+ + An object consists of: + +
+	offset	contents
+	------  --------
+	0:	pointer to vtable
+	4:	monitor
+	8...	non-static members
+	
+ + The vtable consists of: + +
+	0:	pointer to instance of ClassInfo
+	4...	pointers to virtual member functions
+	
+ + The class definition: + +
+	class XXXX
+	{
+	    ....
+	};
+	
+ + Generates the following: + + + +

Interfaces

+ + TBD + +

Arrays

+ + A dynamic array consists of: + +
+	0:	array dimension
+	4:	pointer to array data
+	
+ + A dynamic array is declared as: + +
+	type array[];
+	
+ + whereas a static array is declared as: + +
+	type array[dimension];
+	
+ + Thus, a static array always has the dimension statically available as part of the type, and + so it is implemented like in C. Static array's and Dynamic arrays can be easily converted back + and forth to each other. + + +

Associative Arrays

+ + TBD + +

Reference Types

+ + D has reference types, but they are implicit. For example, classes are always + referred to by reference; this means that class instances can never reside on the stack + or be passed as function parameters. +

+ + When passing a static array to a function, the result, although declared as a static array, will + actually be a reference to a static array. For example: + +

+	int abc[3];
+	
+ + Passing abc to functions results in these implicit conversions: + +
+	void func(int array[3]);	// actually 
+	void func(int *p);		// abc[3] is converted to a pointer to the first element
+	void func(int array[]);	// abc[3] is converted to a dynamic array
+	
+ + +

Name Mangling

+ + TBD + +

Function Calling Conventions

+ + TBD + +

Exception Handling

+ +

Windows

+ + Conforms to the Microsoft Windows Structured Exception Handling + conventions. + TBD + +

Linux

+ + Uses static address range/handler tables. + TBD + +

Garbage Collection

+ + TBD + +

Runtime Helper Functions

+ + TBD + +

Module Initialization and Termination

+ + TBD + +

Unit Testing

+ + TBD + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/acknowledgements.html dmd-0.124/dmd/html/d/acknowledgements.html --- dmd-0.123/dmd/html/d/acknowledgements.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/acknowledgements.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,59 +1,89 @@ - - - -Digital Mars - Acknowledgements - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -


- -

Acknowledgements

- - -The following people have contributed to the D language project; -with ideas, code, expertise, marketing, inspiration -and moral support. -

- Kris Bell, - Hauke Duden, - Bruce Eckel, - Eric Engstrom, - Dave Fladebo, - David Friedman, - Stewart Gordon, - Ben Hinkle, - Jan Knepper, - Thomas Kuehne, - Helmut Leitner, - Lubomir Litchev, - Christopher E. Miller, - Pavel Minayev, - Antonio Monteiro, - Paul Nash, - Pat Nelson, - Burton Radons, - Tim Rentsch, - Fabio Riccardi, - Bob Taniguchi, - John Whited, - Matthew Wilson, - Peter Zatloukal - -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Acknowledgements + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Acknowledgements

+ + +The following people have contributed to the D language project; +with ideas, code, expertise, marketing, inspiration +and moral support. +

+ Kris Bell, + Hauke Duden, + Bruce Eckel, + Eric Engstrom, + Dave Fladebo, + David Friedman, + Stewart Gordon, + Ben Hinkle, + Jan Knepper, + Thomas Kuehne, + Helmut Leitner, + Lubomir Litchev, + Christopher E. Miller, + Pavel Minayev, + Antonio Monteiro, + Paul Nash, + Pat Nelson, + Burton Radons, + Tim Rentsch, + Fabio Riccardi, + Bob Taniguchi, + John Whited, + Matthew Wilson, + Peter Zatloukal + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/arrays.html dmd-0.124/dmd/html/d/arrays.html --- dmd-0.123/dmd/html/d/arrays.html 2005-05-09 01:07:08.000000000 +0200 +++ dmd-0.124/dmd/html/d/arrays.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,1032 +1,1161 @@ - - - - - -D Programming Language - Arrays - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update May 9, 2005 -


- -

Arrays

- - There are four kinds of arrays: - - -
int* p; Pointers to data - -
int[3] s; Static arrays - -
int[] a; Dynamic arrays - -
int[char[]] x; Associative arrays -
- -

Pointers

- -
-	int* p;
-	
- - These are simple pointers to data, analogous to C pointers. - Pointers are provided for interfacing with C and for - specialized systems work. - There - is no length associated with it, and so there is no way for the - compiler or runtime to do bounds checking, etc., on it. - Most conventional uses for pointers can be replaced with - dynamic arrays, out and inout parameters, - and reference types. - -

Static Arrays

- -
-	int[3] s;
-	
- - These are analogous to C arrays. Static arrays are distinguished - by having a length fixed at compile time. -

- - The total size of a static array cannot exceed 16Mb. - A dynamic array should be used instead for such large arrays. - -

Dynamic Arrays

- -
-	int[] a;
-	
- - Dynamic arrays consist of a length and a pointer to the array data. - Multiple dynamic arrays can share all or parts of the array data. - -

Array Declarations

- - There are two ways to declare arrays, prefix and postfix. - The prefix form is the preferred method, especially for - non-trivial types. - -

Prefix Array Declarations

- - Prefix declarations appear before the identifier being - declared and read right to left, so: - -
-	int[] a;	// dynamic array of ints
-	int[4][3] b;	// array of 3 arrays of 4 ints each
-	int[][5] c;	// array of 5 dynamic arrays of ints.
-	int*[]*[3] d;	// array of 3 pointers to dynamic arrays of pointers to ints
-	int[]* e;	// pointer to dynamic array of ints
-	
- - -

Postfix Array Declarations

- - Postfix declarations appear after the identifier being - declared and read left to right. - Each group lists equivalent declarations: - -
-	// dynamic array of ints
-	int[] a;
-	int a[];
-
-	// array of 3 arrays of 4 ints each
-	int[4][3] b;
-	int[4] b[3];
-	int b[3][4];
-
-	// array of 5 dynamic arrays of ints.
-	int[][5] c;
-	int[] c[5];
-	int c[5][];
-
-	// array of 3 pointers to dynamic arrays of pointers to ints
-	int*[]*[3] d;
-	int*[]* d[3];
-	int* (*d[3])[];
-
-	// pointer to dynamic array of ints
-	int[]* e;
-	int (*e[]);
-	
- - Rationale: The postfix form matches the way arrays are - declared in C and C++, and supporting this form provides an - easy migration path for programmers used to it. - -

Usage

- - There are two broad kinds of operations to do on an array - affecting - the handle to the array, - and affecting the contents of the array. - C only has - operators to affect the handle. In D, both are accessible. -

- - The handle to an array is specified by naming the array, as - in p, s or a: - -

-	int* p;
-	int[3] s;
-	int[] a;
-
-	int* q;
-	int[3] t;
-	int[] b;
-
-	p = q;		p points to the same thing q does.
-	p = s;		p points to the first element of the array s.
-	p = a;		p points to the first element of the array a.
-
-	s = ...;	error, since s is a compiled in static
-			reference to an array.
-
-	a = p;		error, since the length of the array pointed
-			to by p is unknown
-	a = s;		a is initialized to point to the s array
-	a = b;		a points to the same array as b does
-    
- -

Slicing

- - Slicing an array means to specify a subarray of it. - An array slice does not copy the data, it is only another - reference to it. - For example: - -
-	int[10] a;	// declare array of 10 ints
-	int[] b;
-
-	b = a[1..3];	// a[1..3] is a 2 element array consisting of
-			// a[1] and a[2]
-	foo(b[1]);	// equivalent to foo(0)
-	a[2] = 3;
-	foo(b[1]);	// equivalent to foo(3)
-    
- - The [] is shorthand for a slice of the entire array. - For example, the assignments to b: - -
-	int[10] a;
-	int[] b;
-
-	b = a;
-	b = a[];
-	b = a[0 .. a.length];
-    
- are all semantically equivalent. -

- - Slicing - is not only handy for referring to parts of other arrays, - but for converting pointers into bounds-checked arrays: - -

-	int* p;
-	int[] b = p[0..8];
-    
- - Slicing for bit arrays is only allowed if the slice's lower - bound falls on a byte boundary: - -
-	bit[] b;
-	...
-	b[0..8];	// ok
-	b[8..16];	// ok
-	b[8..17];	// ok
-	b[1..16];	// error, lower bound is not on a byte boundary
-    
- - Misaligned bit array slices will cause an ArrayBoundsError exception - to be thrown at runtime. - -

Array Copying

- - When the slice operator appears as the lvalue of an assignment - expression, it means that the contents of the array are the - target of the assignment rather than a reference to the array. - Array copying happens when the lvalue is a slice, and the rvalue - is an array of or pointer to the same type. - -
-	int[3] s;
-	int[3] t;
-
-	s[] = t;		the 3 elements of t[3] are copied into s[3]
-	s[] = t[];		the 3 elements of t[3] are copied into s[3]
-	s[1..2] = t[0..1];	same as s[1] = t[0]
-	s[0..2] = t[1..3];	same as s[0] = t[1], s[1] = t[2]
-	s[0..4] = t[0..4];	error, only 3 elements in s
-	s[0..2] = t;		error, different lengths for lvalue and rvalue
-    
- - Overlapping copies are an error: - -
-	s[0..2] = s[1..3];	error, overlapping copy
-	s[1..3] = s[0..2];	error, overlapping copy
- - Disallowing overlapping makes it possible for more aggressive - parallel code optimizations than possible with the serial - semantics of C. - -

Array Setting

- - If a slice operator appears as the lvalue of an assignment - expression, and the type of the rvalue is the same as the element - type of the lvalue, then the lvalue's array contents - are set to the rvalue. - -
-	int[3] s;
-	int* p;
-
-	s[] = 3;		same as s[0] = 3, s[1] = 3, s[2] = 3
-	p[0..2] = 3;		same as p[0] = 3, p[1] = 3
-    
- -

Array Concatenation

- - The binary operator ~ is the cat operator. It is used - to concatenate arrays: - -
-
-	int[] a;
-	int[] b;
-	int[] c;
-
-	a = b ~ c;	Create an array from the concatenation of the
-			b and c arrays
-    
- - Many languages overload the + operator to mean concatenation. - This confusingly leads to, does: - -
-	"10" + 3
-    
- - produce the number 13 or the string "103" as the result? It isn't - obvious, and the language designers wind up carefully writing rules - to disambiguate it - rules that get incorrectly implemented, - overlooked, forgotten, and ignored. It's much better to have + mean - addition, and a separate operator to be array concatenation. -

- - Similarly, the ~= operator means append, as in: - -

-	a ~= b;		a becomes the concatenation of a and b
-    
- - Concatenation always creates a copy of its operands, even - if one of the operands is a 0 length array, so: - -
-	a = b			a refers to b
-	a = b ~ c[0..0]		a refers to a copy of b
-    
- - - -

Array Operations

- - Note: Array operations are not implemented. -

- - In general, (a[n..m] op e) is defined as: - -

-	for (i = n; i < m; i++)
-	    a[i] op e;
-    
- - So, for the expression: - -
-	a[] = b[] + 3;
-    
- - the result is equivalent to: - -
-	for (i = 0; i < a.length; i++)
-	    a[i] = b[i] + 3; 
-    
- - When more than one [] operator appears in an expression, the range - represented by all must match. - -
-	a[1..3] = b[] + 3;	error, 2 elements not same as 3 elements
-    
- -

Examples:

- -
-	int[3] abc;			// static array of 3 ints
-	int[] def = [ 1, 2, 3 ];	// dynamic array of 3 ints
-
-	void dibb(int *array)
-	{
-		array[2];		// means same thing as *(array + 2)
-		*(array + 2);		// get 2nd element
-	}
-
-	void diss(int[] array)
-	{
-		array[2];		// ok
-		*(array + 2);		// error, array is not a pointer
-	}
-
-	void ditt(int[3] array)
-	{
-		array[2];		// ok
-		*(array + 2);		// error, array is not a pointer
-	}
-	
- -

Rectangular Arrays

- - Experienced FORTRAN numerics programmers know that multidimensional - "rectangular" arrays for things like matrix operations are much faster than trying to - access them via pointers to pointers resulting from "array of pointers to array" semantics. - For example, the D syntax: - -
-	double[][] matrix;
-	
- - declares matrix as an array of pointers to arrays. (Dynamic arrays are implemented as - pointers to the array data.) Since the arrays can have varying sizes (being dynamically - sized), this is sometimes called "jagged" arrays. Even worse for optimizing the code, the - array rows can sometimes point to each other! Fortunately, D static arrays, while using - the same syntax, are implemented as a fixed rectangular layout: - -
-	double[3][3] matrix;
-	
- - declares a rectangular matrix with 3 rows and 3 columns, all contiguously in memory. In - other languages, this would be called a multidimensional array and be declared as: - -
-	double matrix[3,3];
-	
- -

Array Length

- - Within the [ ] of a static or a dynamic array, - the variable length - is implicitly declared and set to the length of the array. - -
-	int[4] foo;
-	int[]  bar = foo;
-	int*   p = &foo[0];
-
-	// These expressions are equivalent:
-	bar[]
-	bar[0 .. 4]
-	bar[0 .. length]
-	bar[0 .. bar.length]
-
-	p[0 .. length]	// 'length' is not defined, since p is not an array
-	bar[0]+length	// 'length' is not defined, out of scope of [ ]
-
-	bar[length-1]	// retrieves last element of the array
-	
- -

Array Properties

- - Static array properties are: - - - - - - - -
.sizeof - Returns the array length multiplied by the number of - bytes per array element. - -
.length - Returns the number of elements in the array. - This is a fixed quantity for static arrays. - -
.ptr - Returns a pointer to the first element of the array. - -
.dup - Create a dynamic array of the same size - and copy the contents of the array into it. - -
.reverse - Reverses in place the order of the elements in the array. - Returns the array. - -
.sort - Sorts in place the order of the elements in the array. - Returns the array. - -
-

- - Dynamic array properties are: - - - - - - - - -
.sizeof - Returns the size of the dynamic array reference, - which is 8 on 32 bit machines. - -
.length - Get/set number of elements in the array. - -
.ptr - Returns a pointer to the first element of the array. - -
.dup - Create a dynamic array of the same size - and copy the contents of the array into it. - -
.reverse - Reverses in place the order of the elements in the array. - Returns the array. - -
.sort - Sorts in place the order of the elements in the array. - Returns the array. - -
-

- - Examples: -

-	p.length	error, length not known for pointer
-	s.length	compile time constant 3
-	a.length	runtime value
-
-	p.dup		error, length not known
-	s.dup		creates an array of 3 elements, copies
-			elements s into it
-	a.dup		creates an array of a.length elements, copies
-			elements of a into it
-    
- -

Setting Dynamic Array Length

- - The .length property of a dynamic array can be set - as the lvalue of an = operator: -
-	array.length = 7;
-	
- - This causes the array to be reallocated in place, and the existing - contents copied over to the new array. If the new array length is - shorter, - only enough are copied to fill the new array. If the new array length - is longer, the remainder is filled out with the default initializer. -

- - To maximize efficiency, the runtime always tries to resize the - array in place to avoid extra copying. It will always do a copy - if the new size is larger and the array was not allocated via the - new operator or a previous - resize operation. -

- - This means that if there is an array slice immediately following the - array being resized, the resized array could overlap the slice; i.e.: -

-	char[] a = new char[20];
-	char[] b = a[0..10];
-	char[] c = a[10..20];
-
-	b.length = 15;	// always resized in place because it is sliced
-			// from a[] which has enough memory for 15 chars
-	b[11] = 'x';	// a[15] and c[5] are also affected
-
-	a.length = 1;
-	a.length = 20;	// no net change to memory layout
-
-	c.length = 12;	// always does a copy because c[] is not at the
-			// start of a gc allocation block
-	c[5] = 'y';	// does not affect contents of a[] or b[]
-
-	a.length = 25;	// may or may not do a copy
-	a[3] = 'z';	// may or may not affect b[3] which still overlaps
-			// the old a[3]
-	
- - To guarantee copying behavior, use the .dup property to ensure - a unique array that can be resized. -

- - These issues also apply to concatenating arrays with the ~ and ~= - operators. -

- - Resizing a dynamic array is a relatively expensive operation. - So, while the following method of filling an array: -

-
-	int[] array;
-	while (1)
-	{   c = getinput();
-	    if (!c)
-	       break;
-	    array.length = array.length + 1;
-	    array[array.length - 1] = c;
-	}
-	
- - will work, it will be inefficient. A more practical - approach would be to minimize the number of resizes: - -
-	int[] array;
-	array.length = 100;        // guess
-	for (i = 0; 1; i++)
-	{   c = getinput();
-	     if (!c)
-		break;
-	     if (i == array.length)
-		array.length = array.length * 2;
-	     array[i] = c;
-	}
-	array.length = i;
-	
- - Picking a good initial guess is an art, but you usually can - pick a value covering 99% of the cases. - For example, when gathering user - input from the console - it's unlikely to be longer than 80. - -

Array Bounds Checking

- - It is an error to index an array with an index that is less than - 0 or greater than or equal to the array length. If an index is - out of bounds, an ArrayBoundsError exception is raised if detected - at runtime, and an error if detected at compile time. - A program may not rely on array bounds checking happening, for - example, the following program is incorrect: - -
-	try
-	{
-	    for (i = 0; ; i++)
-	    {
-		array[i] = 5;
-	    }
-	}
-	catch (ArrayBoundsError)
-	{
-	    // terminate loop
-	}
-	
- - The loop is correctly written: - -
-	for (i = 0; i < array.length; i++)
-	{
-	    array[i] = 5;
-	}
-	
- - Implementation Note: Compilers should attempt to detect - array bounds errors at compile time, for example: - -
-	int[3] foo;
-	int x = foo[3];		// error, out of bounds
-	
- - Insertion of array bounds checking code at runtime should be - turned on and off - with a compile time switch. - -

Array Initialization

- - - - -

Static Initialization of Static Arrays

- -
-	int[3] a = [ 1:2, 3 ];		// a[0] = 0, a[1] = 2, a[2] = 3
-	
- - This is most handy when the array indices are given by enums: - -
-	enum Color { red, blue, green };
-
-	int value[Color.max] = [ blue:6, green:2, red:5 ];
-	
- - If any members of an array are initialized, they all must be. - This is to catch - common errors where another element is added to an enum, - but one of the static instances - of arrays of that enum was overlooked in updating the - initializer list. - - -

Special Array Types

- -

Arrays of Bits

- - Bit vectors can be constructed: - -
-	bit[10] x;		// array of 10 bits
-	
- - The amount of storage used up is implementation dependent. - Implementation Note: on - Intel CPUs it would be rounded up to the next 32 bit size. - -
-	x.length		// 10, number of bits
-	x.size			// 4,  bytes of storage
-	
- - So, the size per element is not (x.size / x.length). - - - -

Strings

- - Languages should be good at handling strings. C and C++ are not - good at it. The primary difficulties are memory management, - handling of temporaries, constantly rescanning the string looking - for the terminating 0, and the fixed arrays. -

- - Dynamic arrays in D suggest the obvious solution - a string is - just a dynamic array of characters. String literals become just - an easy way to write character arrays. - -

-	char[] str;
-	char[] str1 = "abc";
-	
- - char[] strings are in UTF-8 format. - wchar[] strings are in UTF-16 format. - dchar[] strings are in UTF-32 format. -

- - Strings can be copied, compared, concatenated, and appended: - -

-	str1 = str2;
-	if (str1 < str3) ...
-	func(str3 ~ str4);
-	str4 ~= str1;
-	
- - with the obvious semantics. Any generated temporaries get cleaned up - by the garbage collector (or by using alloca()). Not only that, - this works with any - array not just a special String array. -

- - A pointer to a char can be generated: - -

-	char *p = &str[3];	// pointer to 4th element
-	char *p = str;		// pointer to 1st element
-	
- - Since strings, however, are not 0 terminated in D, - when transferring a pointer - to a string to C, add a terminating 0: - -
-	str ~= "\0";
-	
- - The type of a string is determined by the semantic phase of - compilation. The type is - one of: char[], wchar[], dchar[], and is determined by - implicit conversion rules. - If there are two equally applicable implicit conversions, - the result is an error. To - disambiguate these cases, a cast is appropriate: - -
-	cast(wchar [])"abc"	// this is an array of wchar characters
-	
- - String literals are implicitly converted between chars, - wchars, and dchars as necessary. -

- - Strings a single character in length can also be exactly - converted to a char, wchar or dchar constant: - -

-	char c;
-	wchar w;
-	dchar d;
-
-	c = 'b';		// c is assigned the character 'b'
-	w = 'b';		// w is assigned the wchar character 'b'
-	w = 'bc';		// error - only one wchar character at a time
-	w = "b"[0];		// w is assigned the wchar character 'b'
-	w = \r;			// w is assigned the carriage return wchar character
-	d = 'd';		// d is assigned the character 'd'
-	
- -

printf() and Strings

- - printf() is a C function and is not part of D. printf() - will print C strings, which are 0 terminated. There are two ways - to use printf() with D strings. The first is to add a - terminating 0, and cast the result to a char*: - -
-	str ~= "\0";
-	printf("the string is '%s'\n", (char *)str);
-	
- - The second way is to use the precision specifier. The way D arrays - are laid out, the length comes first, so the following works: - -
-	printf("the string is '%.*s'\n", str);
-	
- - In the future, it may be necessary to just add a new format - specifier to printf() instead of relying on an implementation - dependent detail. - -

Implicit Conversions

- - A pointer T* can be implicitly converted to - one of the following: - - - - A static array T[dim] can be implicitly - converted to - one of the following: - - - - A dynamic array T[] can be implicitly converted to - one of the following: - - - - - -
-

Associative Arrays

- - D goes one step further with arrays - adding associative arrays. - Associative arrays have an index that is not necessarily an integer, - and can be sparsely populated. The index for an associative array - is called the key, and its type is called the KeyType. -

- - Associative arrays are declared by placing the KeyType - within the [] of an array declaration: - -

-	int[char[]] b;		// associative array b of ints that are
-				// indexed by an array of characters.
-				// The KeyType is char[]
-	b["hello"] = 3;		// set value associated with key "hello" to 3
-	func(b["hello"]);	// pass 3 as parameter to func()
-	
- - Particular keys in an associative array can be removed with the - delete operator: - -
-	delete b["hello"];
-	
- - This confusingly appears to delete the value of b["hello"], but - does not, it removes the key "hello" from the associative array. -

- - The InExpression yields a pointer to the value - if the key is in the associative array, or null if not: - -

-	int* p;
-	p = ("hello" in b);
-	if (p != null)
-		...
-	
- - KeyTypes cannot be functions or voids. -

- - If the KeyType is a struct type, a default mechanism is used - to compute the hash and comparisons of it based on the binary - data within the struct value. A custom mechanism can be used - by providing the following functions as struct members: - -

-	uint toHash();
-	int opCmp(KeyType* s);
-	
- - For example: - -
-	import std.string;
-
-	struct MyString
-	{
-	    char[] str;
-
-	    uint toHash()
-	    {	uint hash;
-		foreach (char c; s)
-		    hash = (hash * 9) + c;
-		return hash;
-	    }
-
-	    int opCmp(MyString* s)
-	    {
-		return std.string.cmp(this.str, s.str);
-	    }
-	}
-	
- -

Properties

- -Properties for associative arrays are: - - - - - - - - -
.size - Returns the size of the reference to the associative - array; it is typically 8. - -
.length - Returns number of values in the associative array. - Unlike for dynamic arrays, it is read-only. - -
.keys - Returns dynamic array, the elements of which are the keys in - the associative array. - -
.values - Returns dynamic array, the elements of which are the values in - the associative array. - -
.rehash - Reorganizes the associative array in place so that lookups - are more efficient. rehash is effective when, for example, - the program is done loading up a symbol table and now needs - fast lookups in it. - Returns a reference to the reorganized array. - -
- -
-

Associative Array Example: word count

- -
-    import std.file;		// D file I/O
-
-    int main (char[][] args)
-    {
-	int word_total;
-	int line_total;
-	int char_total;
-	int[char[]] dictionary;
-
-	printf("   lines   words   bytes file\n");
-	for (int i = 1; i < args.length; ++i)	// program arguments
-	{
-	    char[] input;		// input buffer
-	    int w_cnt, l_cnt, c_cnt;	// word, line, char counts
-	    int inword;
-	    int wstart;
-
-	    input = std.file.read(args[i]);	// read file into input[]
-
-	    foreach (char c; input)
-	    {
-		if (c == '\n')
-		    ++l_cnt;
-		if (c >= '0' && c <= '9')
-		{
-		}
-		else if (c >= 'a' && c <= 'z' ||
-		    c >= 'A' && c <= 'Z')
-		{
-		    if (!inword)
-		    {
-			wstart = j;
-			inword = 1;
-			++w_cnt;
-		    }
-		}
-		else if (inword)
-		{   char[] word = input[wstart .. j];
-
-		    dictionary[word]++;		// increment count for word
-		    inword = 0;
-		}
-		++c_cnt;
-	    }
-	    if (inword)
-	    {   char[] word = input[wstart .. input.length];
-		dictionary[word]++;
-	    }
-	    printf("%8ld%8ld%8ld %.*s\n", l_cnt, w_cnt, c_cnt, args[i]);
-	    line_total += l_cnt;
-	    word_total += w_cnt;
-	    char_total += c_cnt;
-	}
-
-	if (args.length > 2)
-	{
-	    printf("-------------------------------------\n%8ld%8ld%8ld total",
-		line_total, word_total, char_total);
-	}
-
-	printf("-------------------------------------\n");
-	char[][] keys = dictionary.keys;	// find all words in dictionary[]
-	for (int i = 0; i < keys.length; i++)
-	{   char[] word;
-
-	    word = keys[i];
-	    printf("%3d %.*s\n", dictionary[word], word);
-	}
-	return 0;
-    }
-    
- -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Arrays + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

Arrays

+ + There are four kinds of arrays: + + +
int* p; Pointers to data + +
int[3] s; Static arrays + +
int[] a; Dynamic arrays + +
int[char[]] x; Associative arrays +
+ +

Pointers

+ +

+
+

+	int* p;
+	

+ + These are simple pointers to data, analogous to C pointers. + Pointers are provided for interfacing with C and for + specialized systems work. + There + is no length associated with it, and so there is no way for the + compiler or runtime to do bounds checking, etc., on it. + Most conventional uses for pointers can be replaced with + dynamic arrays, out and inout parameters, + and reference types. + +

Static Arrays

+ +

+
+

+	int[3] s;
+	

+ + These are analogous to C arrays. Static arrays are distinguished + by having a length fixed at compile time. +

+ + The total size of a static array cannot exceed 16Mb. + A dynamic array should be used instead for such large arrays. + +

Dynamic Arrays

+ +

+
+

+	int[] a;
+	

+ + Dynamic arrays consist of a length and a pointer to the array data. + Multiple dynamic arrays can share all or parts of the array data. + +

Array Declarations

+ + There are two ways to declare arrays, prefix and postfix. + The prefix form is the preferred method, especially for + non-trivial types. + +

Prefix Array Declarations

+ + Prefix declarations appear before the identifier being + declared and read right to left, so: + +

+
+

+	int[] a;	// dynamic array of ints
+	int[4][3] b;	// array of 3 arrays of 4 ints each
+	int[][5] c;	// array of 5 dynamic arrays of ints.
+	int*[]*[3] d;	// array of 3 pointers to dynamic arrays of pointers to ints
+	int[]* e;	// pointer to dynamic array of ints
+	

+ + +

Postfix Array Declarations

+ + Postfix declarations appear after the identifier being + declared and read left to right. + Each group lists equivalent declarations: + +

+
+

+	// dynamic array of ints
+	int[] a;
+	int a[];
+
+	// array of 3 arrays of 4 ints each
+	int[4][3] b;
+	int[4] b[3];
+	int b[3][4];
+
+	// array of 5 dynamic arrays of ints.
+	int[][5] c;
+	int[] c[5];
+	int c[5][];
+
+	// array of 3 pointers to dynamic arrays of pointers to ints
+	int*[]*[3] d;
+	int*[]* d[3];
+	int* (*d[3])[];
+
+	// pointer to dynamic array of ints
+	int[]* e;
+	int (*e[]);
+	

+ + Rationale: The postfix form matches the way arrays are + declared in C and C++, and supporting this form provides an + easy migration path for programmers used to it. + +

Usage

+ + There are two broad kinds of operations to do on an array - affecting + the handle to the array, + and affecting the contents of the array. + C only has + operators to affect the handle. In D, both are accessible. +

+ + The handle to an array is specified by naming the array, as + in p, s or a: + +

+
+

+	int* p;
+	int[3] s;
+	int[] a;
+
+	int* q;
+	int[3] t;
+	int[] b;
+
+	p = q;		p points to the same thing q does.
+	p = s;		p points to the first element of the array s.
+	p = a;		p points to the first element of the array a.
+
+	s = ...;	error, since s is a compiled in static
+			reference to an array.
+
+	a = p;		error, since the length of the array pointed
+			to by p is unknown
+	a = s;		a is initialized to point to the s array
+	a = b;		a points to the same array as b does
+    

+ +

Slicing

+ + Slicing an array means to specify a subarray of it. + An array slice does not copy the data, it is only another + reference to it. + For example: + +

+
+

+	int[10] a;	// declare array of 10 ints
+	int[] b;
+
+	b = a[1..3];	// a[1..3] is a 2 element array consisting of
+			// a[1] and a[2]
+	foo(b[1]);	// equivalent to foo(0)
+	a[2] = 3;
+	foo(b[1]);	// equivalent to foo(3)
+    

+ + The [] is shorthand for a slice of the entire array. + For example, the assignments to b: + +

+
+

+	int[10] a;
+	int[] b;
+
+	b = a;
+	b = a[];
+	b = a[0 .. a.length];
+    

+ are all semantically equivalent. +

+ + Slicing + is not only handy for referring to parts of other arrays, + but for converting pointers into bounds-checked arrays: + +

+
+

+	int* p;
+	int[] b = p[0..8];
+    

+ + Slicing for bit arrays is only allowed if the slice's lower + bound falls on a byte boundary: + +

+
+

+	bit[] b;
+	...
+	b[0..8];	// ok
+	b[8..16];	// ok
+	b[8..17];	// ok
+	b[1..16];	// error, lower bound is not on a byte boundary
+    

+ + Misaligned bit array slices will cause an ArrayBoundsError exception + to be thrown at runtime. + +

Array Copying

+ + When the slice operator appears as the lvalue of an assignment + expression, it means that the contents of the array are the + target of the assignment rather than a reference to the array. + Array copying happens when the lvalue is a slice, and the rvalue + is an array of or pointer to the same type. + +

+
+

+	int[3] s;
+	int[3] t;
+
+	s[] = t;		the 3 elements of t[3] are copied into s[3]
+	s[] = t[];		the 3 elements of t[3] are copied into s[3]
+	s[1..2] = t[0..1];	same as s[1] = t[0]
+	s[0..2] = t[1..3];	same as s[0] = t[1], s[1] = t[2]
+	s[0..4] = t[0..4];	error, only 3 elements in s
+	s[0..2] = t;		error, different lengths for lvalue and rvalue
+    

+ + Overlapping copies are an error: + +

+
+

+	s[0..2] = s[1..3];	error, overlapping copy
+	s[1..3] = s[0..2];	error, overlapping copy

+ + Disallowing overlapping makes it possible for more aggressive + parallel code optimizations than possible with the serial + semantics of C. + +

Array Setting

+ + If a slice operator appears as the lvalue of an assignment + expression, and the type of the rvalue is the same as the element + type of the lvalue, then the lvalue's array contents + are set to the rvalue. + +

+
+

+	int[3] s;
+	int* p;
+
+	s[] = 3;		same as s[0] = 3, s[1] = 3, s[2] = 3
+	p[0..2] = 3;		same as p[0] = 3, p[1] = 3
+    

+ +

Array Concatenation

+ + The binary operator ~ is the cat operator. It is used + to concatenate arrays: + +

+
+

+
+	int[] a;
+	int[] b;
+	int[] c;
+
+	a = b ~ c;	Create an array from the concatenation of the
+			b and c arrays
+    

+ + Many languages overload the + operator to mean concatenation. + This confusingly leads to, does: + +

+
+

+	"10" + 3
+    

+ + produce the number 13 or the string "103" as the result? It isn't + obvious, and the language designers wind up carefully writing rules + to disambiguate it - rules that get incorrectly implemented, + overlooked, forgotten, and ignored. It's much better to have + mean + addition, and a separate operator to be array concatenation. +

+ + Similarly, the ~= operator means append, as in: + +

+
+

+	a ~= b;		a becomes the concatenation of a and b
+    

+ + Concatenation always creates a copy of its operands, even + if one of the operands is a 0 length array, so: + +

+
+

+	a = b			a refers to b
+	a = b ~ c[0..0]		a refers to a copy of b
+    

+ + + +

Array Operations

+ + Note: Array operations are not implemented. +

+ + In general, (a[n..m] op e) is defined as: + +

+
+

+	for (i = n; i < m; i++)
+	    a[i] op e;
+    

+ + So, for the expression: + +

+
+

+	a[] = b[] + 3;
+    

+ + the result is equivalent to: + +

+
+

+	for (i = 0; i < a.length; i++)
+	    a[i] = b[i] + 3; 
+    

+ + When more than one [] operator appears in an expression, the range + represented by all must match. + +

+
+

+	a[1..3] = b[] + 3;	error, 2 elements not same as 3 elements
+    

+ +

Examples:

+ +

+
+

+	int[3] abc;			// static array of 3 ints
+	int[] def = [ 1, 2, 3 ];	// dynamic array of 3 ints
+
+	void dibb(int *array)
+	{
+		array[2];		// means same thing as *(array + 2)
+		*(array + 2);		// get 2nd element
+	}
+
+	void diss(int[] array)
+	{
+		array[2];		// ok
+		*(array + 2);		// error, array is not a pointer
+	}
+
+	void ditt(int[3] array)
+	{
+		array[2];		// ok
+		*(array + 2);		// error, array is not a pointer
+	}
+	

+ +

Rectangular Arrays

+ + Experienced FORTRAN numerics programmers know that multidimensional + "rectangular" arrays for things like matrix operations are much faster than trying to + access them via pointers to pointers resulting from "array of pointers to array" semantics. + For example, the D syntax: + +

+
+

+	double[][] matrix;
+	

+ + declares matrix as an array of pointers to arrays. (Dynamic arrays are implemented as + pointers to the array data.) Since the arrays can have varying sizes (being dynamically + sized), this is sometimes called "jagged" arrays. Even worse for optimizing the code, the + array rows can sometimes point to each other! Fortunately, D static arrays, while using + the same syntax, are implemented as a fixed rectangular layout: + +

+
+

+	double[3][3] matrix;
+	

+ + declares a rectangular matrix with 3 rows and 3 columns, all contiguously in memory. In + other languages, this would be called a multidimensional array and be declared as: + +

+
+

+	double matrix[3,3];
+	

+ +

Array Length

+ + Within the [ ] of a static or a dynamic array, + the variable length + is implicitly declared and set to the length of the array. + +

+
+

+	int[4] foo;
+	int[]  bar = foo;
+	int*   p = &foo[0];
+
+	// These expressions are equivalent:
+	bar[]
+	bar[0 .. 4]
+	bar[0 .. length]
+	bar[0 .. bar.length]
+
+	p[0 .. length]	// 'length' is not defined, since p is not an array
+	bar[0]+length	// 'length' is not defined, out of scope of [ ]
+
+	bar[length-1]	// retrieves last element of the array
+	

+ +

Array Properties

+ + Static array properties are: + + + + + + + +
.sizeof + Returns the array length multiplied by the number of + bytes per array element. + +
.length + Returns the number of elements in the array. + This is a fixed quantity for static arrays. + +
.ptr + Returns a pointer to the first element of the array. + +
.dup + Create a dynamic array of the same size + and copy the contents of the array into it. + +
.reverse + Reverses in place the order of the elements in the array. + Returns the array. + +
.sort + Sorts in place the order of the elements in the array. + Returns the array. + +
+

+ + Dynamic array properties are: + + + + + + + + +
.sizeof + Returns the size of the dynamic array reference, + which is 8 on 32 bit machines. + +
.length + Get/set number of elements in the array. + +
.ptr + Returns a pointer to the first element of the array. + +
.dup + Create a dynamic array of the same size + and copy the contents of the array into it. + +
.reverse + Reverses in place the order of the elements in the array. + Returns the array. + +
.sort + Sorts in place the order of the elements in the array. + Returns the array. + +
+

+ + Examples: +

+
+

+	p.length	error, length not known for pointer
+	s.length	compile time constant 3
+	a.length	runtime value
+
+	p.dup		error, length not known
+	s.dup		creates an array of 3 elements, copies
+			elements s into it
+	a.dup		creates an array of a.length elements, copies
+			elements of a into it
+    

+ +

Setting Dynamic Array Length

+ + The .length property of a dynamic array can be set + as the lvalue of an = operator: +

+
+

+	array.length = 7;
+	

+ + This causes the array to be reallocated in place, and the existing + contents copied over to the new array. If the new array length is + shorter, + only enough are copied to fill the new array. If the new array length + is longer, the remainder is filled out with the default initializer. +

+ + To maximize efficiency, the runtime always tries to resize the + array in place to avoid extra copying. It will always do a copy + if the new size is larger and the array was not allocated via the + new operator or a previous + resize operation. +

+ + This means that if there is an array slice immediately following the + array being resized, the resized array could overlap the slice; i.e.: +

+
+

+	char[] a = new char[20];
+	char[] b = a[0..10];
+	char[] c = a[10..20];
+
+	b.length = 15;	// always resized in place because it is sliced
+			// from a[] which has enough memory for 15 chars
+	b[11] = 'x';	// a[15] and c[5] are also affected
+
+	a.length = 1;
+	a.length = 20;	// no net change to memory layout
+
+	c.length = 12;	// always does a copy because c[] is not at the
+			// start of a gc allocation block
+	c[5] = 'y';	// does not affect contents of a[] or b[]
+
+	a.length = 25;	// may or may not do a copy
+	a[3] = 'z';	// may or may not affect b[3] which still overlaps
+			// the old a[3]
+	

+ + To guarantee copying behavior, use the .dup property to ensure + a unique array that can be resized. +

+ + These issues also apply to concatenating arrays with the ~ and ~= + operators. +

+ + Resizing a dynamic array is a relatively expensive operation. + So, while the following method of filling an array: +

+
+

+
+	int[] array;
+	while (1)
+	{   c = getinput();
+	    if (!c)
+	       break;
+	    array.length = array.length + 1;
+	    array[array.length - 1] = c;
+	}
+	

+ + will work, it will be inefficient. A more practical + approach would be to minimize the number of resizes: + +

+
+

+	int[] array;
+	array.length = 100;        // guess
+	for (i = 0; 1; i++)
+	{   c = getinput();
+	     if (!c)
+		break;
+	     if (i == array.length)
+		array.length = array.length * 2;
+	     array[i] = c;
+	}
+	array.length = i;
+	

+ + Picking a good initial guess is an art, but you usually can + pick a value covering 99% of the cases. + For example, when gathering user + input from the console - it's unlikely to be longer than 80. + +

Array Bounds Checking

+ + It is an error to index an array with an index that is less than + 0 or greater than or equal to the array length. If an index is + out of bounds, an ArrayBoundsError exception is raised if detected + at runtime, and an error if detected at compile time. + A program may not rely on array bounds checking happening, for + example, the following program is incorrect: + +

+
+

+	try
+	{
+	    for (i = 0; ; i++)
+	    {
+		array[i] = 5;
+	    }
+	}
+	catch (ArrayBoundsError)
+	{
+	    // terminate loop
+	}
+	

+ + The loop is correctly written: + +

+
+

+	for (i = 0; i < array.length; i++)
+	{
+	    array[i] = 5;
+	}
+	

+ + Implementation Note: Compilers should attempt to detect + array bounds errors at compile time, for example: + +

+
+

+	int[3] foo;
+	int x = foo[3];		// error, out of bounds
+	

+ + Insertion of array bounds checking code at runtime should be + turned on and off + with a compile time switch. + +

Array Initialization

+ + + + +

Static Initialization of Static Arrays

+ +

+
+

+	int[3] a = [ 1:2, 3 ];		// a[0] = 0, a[1] = 2, a[2] = 3
+	

+ + This is most handy when the array indices are given by enums: + +

+
+

+	enum Color { red, blue, green };
+
+	int value[Color.max] = [ blue:6, green:2, red:5 ];
+	

+ + If any members of an array are initialized, they all must be. + This is to catch + common errors where another element is added to an enum, + but one of the static instances + of arrays of that enum was overlooked in updating the + initializer list. + + +

Special Array Types

+ +

Arrays of Bits

+ + Bit vectors can be constructed: + +

+
+

+	bit[10] x;		// array of 10 bits
+	

+ + The amount of storage used up is implementation dependent. + Implementation Note: on + Intel CPUs it would be rounded up to the next 32 bit size. + +

+
+

+	x.length		// 10, number of bits
+	x.size			// 4,  bytes of storage
+	

+ + So, the size per element is not (x.size / x.length). + + + +

Strings

+ + Languages should be good at handling strings. C and C++ are not + good at it. The primary difficulties are memory management, + handling of temporaries, constantly rescanning the string looking + for the terminating 0, and the fixed arrays. +

+ + Dynamic arrays in D suggest the obvious solution - a string is + just a dynamic array of characters. String literals become just + an easy way to write character arrays. + +

+
+

+	char[] str;
+	char[] str1 = "abc";
+	

+ + char[] strings are in UTF-8 format. + wchar[] strings are in UTF-16 format. + dchar[] strings are in UTF-32 format. +

+ + Strings can be copied, compared, concatenated, and appended: + +

+
+

+	str1 = str2;
+	if (str1 < str3) ...
+	func(str3 ~ str4);
+	str4 ~= str1;
+	

+ + with the obvious semantics. Any generated temporaries get cleaned up + by the garbage collector (or by using alloca()). Not only that, + this works with any + array not just a special String array. +

+ + A pointer to a char can be generated: + +

+
+

+	char *p = &str[3];	// pointer to 4th element
+	char *p = str;		// pointer to 1st element
+	

+ + Since strings, however, are not 0 terminated in D, + when transferring a pointer + to a string to C, add a terminating 0: + +

+
+

+	str ~= "\0";
+	

+ + The type of a string is determined by the semantic phase of + compilation. The type is + one of: char[], wchar[], dchar[], and is determined by + implicit conversion rules. + If there are two equally applicable implicit conversions, + the result is an error. To + disambiguate these cases, a cast is appropriate: + +

+
+

+	cast(wchar [])"abc"	// this is an array of wchar characters
+	

+ + String literals are implicitly converted between chars, + wchars, and dchars as necessary. +

+ + Strings a single character in length can also be exactly + converted to a char, wchar or dchar constant: + +

+
+

+	char c;
+	wchar w;
+	dchar d;
+
+	c = 'b';		// c is assigned the character 'b'
+	w = 'b';		// w is assigned the wchar character 'b'
+	w = 'bc';		// error - only one wchar character at a time
+	w = "b"[0];		// w is assigned the wchar character 'b'
+	w = \r;			// w is assigned the carriage return wchar character
+	d = 'd';		// d is assigned the character 'd'
+	

+ +

printf() and Strings

+ + printf() is a C function and is not part of D. printf() + will print C strings, which are 0 terminated. There are two ways + to use printf() with D strings. The first is to add a + terminating 0, and cast the result to a char*: + +

+
+

+	str ~= "\0";
+	printf("the string is '%s'\n", (char *)str);
+	

+ + The second way is to use the precision specifier. The way D arrays + are laid out, the length comes first, so the following works: + +

+
+

+	printf("the string is '%.*s'\n", str);
+	

+ + In the future, it may be necessary to just add a new format + specifier to printf() instead of relying on an implementation + dependent detail. + +

Implicit Conversions

+ + A pointer T* can be implicitly converted to + one of the following: + + + + A static array T[dim] can be implicitly + converted to + one of the following: + + + + A dynamic array T[] can be implicitly converted to + one of the following: + + + + + +
+

Associative Arrays

+ + D goes one step further with arrays - adding associative arrays. + Associative arrays have an index that is not necessarily an integer, + and can be sparsely populated. The index for an associative array + is called the key, and its type is called the KeyType. +

+ + Associative arrays are declared by placing the KeyType + within the [] of an array declaration: + +

+
+

+	int[char[]] b;		// associative array b of ints that are
+				// indexed by an array of characters.
+				// The KeyType is char[]
+	b["hello"] = 3;		// set value associated with key "hello" to 3
+	func(b["hello"]);	// pass 3 as parameter to func()
+	

+ + Particular keys in an associative array can be removed with the + delete operator: + +

+
+

+	delete b["hello"];
+	

+ + This confusingly appears to delete the value of b["hello"], but + does not, it removes the key "hello" from the associative array. +

+ + The InExpression yields a pointer to the value + if the key is in the associative array, or null if not: + +

+
+

+	int* p;
+	p = ("hello" in b);
+	if (p != null)
+		...
+	

+ + KeyTypes cannot be functions or voids. +

+ + If the KeyType is a struct type, a default mechanism is used + to compute the hash and comparisons of it based on the binary + data within the struct value. A custom mechanism can be used + by providing the following functions as struct members: + +

+
+

+	uint toHash();
+	int opCmp(KeyType* s);
+	

+ + For example: + +

+
+

+	import std.string;
+
+	struct MyString
+	{
+	    char[] str;
+
+	    uint toHash()
+	    {	uint hash;
+		foreach (char c; s)
+		    hash = (hash * 9) + c;
+		return hash;
+	    }
+
+	    int opCmp(MyString* s)
+	    {
+		return std.string.cmp(this.str, s.str);
+	    }
+	}
+	

+ +

Properties

+ +Properties for associative arrays are: + + + + + + + + +
.size + Returns the size of the reference to the associative + array; it is typically 8. + +
.length + Returns number of values in the associative array. + Unlike for dynamic arrays, it is read-only. + +
.keys + Returns dynamic array, the elements of which are the keys in + the associative array. + +
.values + Returns dynamic array, the elements of which are the values in + the associative array. + +
.rehash + Reorganizes the associative array in place so that lookups + are more efficient. rehash is effective when, for example, + the program is done loading up a symbol table and now needs + fast lookups in it. + Returns a reference to the reorganized array. + +
+ +
+

Associative Array Example: word count

+ +

+
+

+    import std.file;		// D file I/O
+
+    int main (char[][] args)
+    {
+	int word_total;
+	int line_total;
+	int char_total;
+	int[char[]] dictionary;
+
+	printf("   lines   words   bytes file\n");
+	for (int i = 1; i < args.length; ++i)	// program arguments
+	{
+	    char[] input;		// input buffer
+	    int w_cnt, l_cnt, c_cnt;	// word, line, char counts
+	    int inword;
+	    int wstart;
+
+	    input = std.file.read(args[i]);	// read file into input[]
+
+	    foreach (char c; input)
+	    {
+		if (c == '\n')
+		    ++l_cnt;
+		if (c >= '0' && c <= '9')
+		{
+		}
+		else if (c >= 'a' && c <= 'z' ||
+		    c >= 'A' && c <= 'Z')
+		{
+		    if (!inword)
+		    {
+			wstart = j;
+			inword = 1;
+			++w_cnt;
+		    }
+		}
+		else if (inword)
+		{   char[] word = input[wstart .. j];
+
+		    dictionary[word]++;		// increment count for word
+		    inword = 0;
+		}
+		++c_cnt;
+	    }
+	    if (inword)
+	    {   char[] word = input[wstart .. input.length];
+		dictionary[word]++;
+	    }
+	    printf("%8ld%8ld%8ld %.*s\n", l_cnt, w_cnt, c_cnt, args[i]);
+	    line_total += l_cnt;
+	    word_total += w_cnt;
+	    char_total += c_cnt;
+	}
+
+	if (args.length > 2)
+	{
+	    printf("-------------------------------------\n%8ld%8ld%8ld total",
+		line_total, word_total, char_total);
+	}
+
+	printf("-------------------------------------\n");
+	char[][] keys = dictionary.keys;	// find all words in dictionary[]
+	for (int i = 0; i < keys.length; i++)
+	{   char[] word;
+
+	    word = keys[i];
+	    printf("%3d %.*s\n", dictionary[word], word);
+	}
+	return 0;
+    }
+    

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + + diff -uNr dmd-0.123/dmd/html/d/attribute.html dmd-0.124/dmd/html/d/attribute.html --- dmd-0.123/dmd/html/d/attribute.html 2005-05-08 16:31:38.000000000 +0200 +++ dmd-0.124/dmd/html/d/attribute.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,423 +1,483 @@ - - - - - -D Programming Language - Attributes - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last modified May 8, 2005. -


- -

Attributes

- -
-	AttributeSpecifier:
-	    Attribute :
-	    Attribute DeclDefBlock
-	    Pragma ;
-
-	AttributeElseSpecifier:
-	    AttributeElse :
-	    AttributeElse DeclDefBlock
-	    AttributeElse DeclDefBlock else DeclDefBlock
-
-	Attribute:
-	    LinkageAttribute
-	    AlignAttribute
-	    Pragma
-	    deprecated
-	    private
-	    package
-	    protected
-	    public
-	    export
-	    static
-	    final
-	    override
-	    abstract
-	    const
-	    auto
-
-	AttributeElse:
-	    DebugAttribute
-	    VersionAttribute
-
-	DeclDefBlock
-	    DeclDef
-	    { }
-	    { DeclDefs }
-	
- - Attributes are a way to modify one or more declarations. - The general forms are: - -
-	attribute declaration;		affects the declaration
-
-	attribute:			affects all declarations until the next }
-	    declaration;
-	    declaration;
-	    ...
-
-	attribute			affects all declarations in the block
-	{
-	    declaration;
-	    declaration;
-	    ...
-	}
-	
- - For attributes with an optional else clause: - -
-	attribute
-	    declaration;
-	else
-	    declaration;
-
-	attribute			affects all declarations in the block
-	{
-	    declaration;
-	    declaration;
-	    ...
-	}
-	else
-	{
-	    declaration;
-	    declaration;
-	    ...
-	}
-	
- -

Linkage Attribute

- -
-	LinkageAttribute:
-		extern
-		extern ( LinkageType )
-
-	LinkageType:
-		C
-		C++
-		D
-		Windows
-		Pascal
-	
- - D provides an easy way to call C functions and operating - system API functions, as compatibility with both is essential. - The LinkageType is case sensitive, and is meant to be - extensible by the implementation (they are not keywords). - C and D must be supplied, the others are what - makes sense for the implementation. - C++ is reserved for future use. - Implementation Note: - for Win32 platforms, Windows and Pascal should exist. -

- - C function calling conventions are - specified by: - -

-	extern (C):
-		int foo();	call foo() with C conventions
-	
- - D conventions are: - -
-	extern (D):
-	
- - or: - -
-	extern:
-	
- - - Windows API conventions are: - -
-	extern (Windows):
-	    void *VirtualAlloc(
-	    void *lpAddress,
-	    uint dwSize,
-	    uint flAllocationType,
-	    uint flProtect
-	    );
-	
- -

Align Attribute

- -
-	AlignAttribute:
-		align
-		align ( Integer )
-	
- - Specifies the alignment of struct members. align by itself - sets it to the default, which matches the default member alignment - of the companion C compiler. Integer specifies the alignment - which matches the behavior of the companion C compiler when non-default - alignments are used. -

- - Matching the behavior of the companion C compiler can have some - surprising results, such as the following for Digital Mars C++: - -

-	struct S
-	{   align(4) byte a;	// placed at offset 0
-	    align(4) byte b;	// placed at offset 1
-	}
- - AlignAttribute is meant for C ABI compatiblity, which is not - the same thing as binary compatibility across diverse platforms. - For that, use packed structs: - -
-	align (1) struct S
-	{   byte a;	// placed at offset 0
-	    byte[3] filler1;
-	    byte b;	// placed at offset 4
-	    byte[3] filler2;
-	}
- - A value of 1 means that no alignment is done; - members are packed together. -

- - Do not align references or pointers that were allocated - using NewExpression on boundaries that are not - a multipe of 4. The garbage collector assumes that pointers - and references to gc allocated objects will be on 4 - byte boundaries. If they are not, undefined behavior will - result. -

- - AlignAttribute is ignored when applied to declarations - that are not structs or struct members. - -

Deprecated Attribute

- - It is often necessary to deprecate a feature in a library, - yet retain it for backwards compatibility. Such - declarations can be marked as deprecated, which means - that the compiler can be set to produce an error - if any code refers to deprecated - declarations: - -
-	deprecated
-	{
-		void oldFoo();
-	}
-	
- - Implementation Note: The compiler should have a switch - specifying if deprecated declarations should be compiled with - out complaint or not. - - -

Protection Attribute

- - Protection is an attribute that is one of - private, package, protected, - public or export. -

- - Private means that only members of the enclosing class can access - the member, or members and functions in the same module as the - enclosing class. - Private members cannot be overridden. - Private module members are equivalent to static declarations - in C programs. -

- - Package extends private so that package members can be accessed - from code in other modules that are in the same package. - This applies to the innermost package only, if a module is in - nested packages. -

- - Protected means that only members of the enclosing class or any - classes derived - from that class, or members and functions in the same module - as the enclosing class, can access the member. - Protected module members are illegal. -

- - Public means that any code within the executable can access the member. -

- - Export means that any code outside the executable can access the - member. Export - is analogous to exporting definitions from a DLL. - -

Const Attribute

- -
-	const
-	
- - The const attribute declares constants that can be - evaluated at compile time. For example: - -
-	const int foo = 7;
-
-	const
-	{
-	    double bar = foo + 6;
-	}
-	
- -

Override Attribute

- -
-	override
-	
- - The override attribute applies to virtual functions. - It means that the function must override a function with the - same name and parameters in a base class. The override attribute - is useful for catching errors when a base class's member function - gets its parameters changed, and all derived classes need to have - their overriding functions updated. - -
-	class Foo
-	{
-	    int bar();
-	    int abc(int x);
-	}
-
-	class Foo2 : Foo
-	{
-	    override
-	    {
-		int bar(char c);	// error, no bar(char) in Foo
-		int abc(int x);		// ok
-	    }
-	}
-	
- -

Static Attribute

- -
-	static
-	
- - The static attribute applies to functions and data. - It means that the declaration does not apply to a particular - instance of an object, but to the type of the object. In - other words, it means there is no this reference. - static is ignored when applied to other declarations. - -
-	class Foo
-	{
-	    static int bar() { return 6; }
-	    int foobar() { return 7; }
-	}
-
-	...
-
-	Foo f = new Foo;
-	Foo.bar();	// produces 6
-	Foo.foobar();	// error, no instance of Foo
-	f.bar();	// produces 6;
-	f.foobar();	// produces 7;
-	
- - Static functions are never virtual. -

- - Static data has only one instance for the entire program, - not once per object. -

- - Static does not have the additional C meaning of being local - to a file. Use the private attribute in D to achieve that. - For example: - -

-	module foo;
-	int x = 3;		// x is global
-	private int y = 4;	// y is local to module foo
-	
- - -

Auto Attribute

- -
-	auto
-	
- - The auto attribute is used for local variables and for class - declarations. For class declarations, the auto attribute creates - an auto class. - For local declarations, auto implements the RAII (Resource - Acquisition Is Initialization) protocol. This means that the - destructor for an object is automatically called when the auto - reference to it goes out of scope. The destructor is called even - if the scope is exited via a thrown exception, thus auto - is used to guarantee cleanup. -

- - If there is more than one auto variable going out of scope - at the same point, then the destructors are called in the reverse - order that the variables were constructed. -

- - Auto cannot be applied to globals, statics, data members, inout - or out parameters. Arrays of autos are not allowed, and auto - function return values are not allowed. Assignment to an auto, - other than initialization, is not allowed. - Rationale: These restrictions may get relaxed in the future - if a compelling reason to appears. - - -

Abstract Attribute

- - If a class is abstract, it cannot be instantiated - directly. It can only be instantiated as a base class of - another, non-abstract, class. -

- - Classes become abstract if they are defined within an - abstract attribute, or if any of the virtual member functions - within it are declared as abstract. -

- - Non-virtual functions cannot be declared as abstract. -

- - Functions declared as abstract can still have function - bodies. This is so that even though they must be overridden, - they can still provide 'base class functionality.' - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Attributes + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

Attributes

+ +

+
+

+	AttributeSpecifier:
+	    Attribute :
+	    Attribute DeclDefBlock
+	    Pragma ;
+
+	AttributeElseSpecifier:
+	    AttributeElse :
+	    AttributeElse DeclDefBlock
+	    AttributeElse DeclDefBlock else DeclDefBlock
+
+	Attribute:
+	    LinkageAttribute
+	    AlignAttribute
+	    Pragma
+	    deprecated
+	    private
+	    package
+	    protected
+	    public
+	    export
+	    static
+	    final
+	    override
+	    abstract
+	    const
+	    auto
+
+	AttributeElse:
+	    DebugAttribute
+	    VersionAttribute
+
+	DeclDefBlock
+	    DeclDef
+	    { }
+	    { DeclDefs }
+	

+ + Attributes are a way to modify one or more declarations. + The general forms are: + +

+	attribute declaration;		affects the declaration
+
+	attribute:			affects all declarations until the next }
+	    declaration;
+	    declaration;
+	    ...
+
+	attribute			affects all declarations in the block
+	{
+	    declaration;
+	    declaration;
+	    ...
+	}
+	
+ + For attributes with an optional else clause: + +
+	attribute
+	    declaration;
+	else
+	    declaration;
+
+	attribute			affects all declarations in the block
+	{
+	    declaration;
+	    declaration;
+	    ...
+	}
+	else
+	{
+	    declaration;
+	    declaration;
+	    ...
+	}
+	
+ +

Linkage Attribute

+ +

+
+

+	LinkageAttribute:
+		extern
+		extern ( LinkageType )
+
+	LinkageType:
+		C
+		C++
+		D
+		Windows
+		Pascal
+	

+ + D provides an easy way to call C functions and operating + system API functions, as compatibility with both is essential. + The LinkageType is case sensitive, and is meant to be + extensible by the implementation (they are not keywords). + C and D must be supplied, the others are what + makes sense for the implementation. + C++ is reserved for future use. + Implementation Note: + for Win32 platforms, Windows and Pascal should exist. +

+ + C function calling conventions are + specified by: + +

+
+

+	extern (C):
+		int foo();	call foo() with C conventions
+	

+ + D conventions are: + +

+
+

+	extern (D):
+	

+ + or: + +

+
+

+	extern:
+	

+ + + Windows API conventions are: + +

+
+

+	extern (Windows):
+	    void *VirtualAlloc(
+	    void *lpAddress,
+	    uint dwSize,
+	    uint flAllocationType,
+	    uint flProtect
+	    );
+	

+ +

Align Attribute

+ +

+
+

+	AlignAttribute:
+		align
+		align ( Integer )
+	

+ + Specifies the alignment of struct members. align by itself + sets it to the default, which matches the default member alignment + of the companion C compiler. Integer specifies the alignment + which matches the behavior of the companion C compiler when non-default + alignments are used. +

+ + Matching the behavior of the companion C compiler can have some + surprising results, such as the following for Digital Mars C++: + +

+
+

+	struct S
+	{   align(4) byte a;	// placed at offset 0
+	    align(4) byte b;	// placed at offset 1
+	}

+ + AlignAttribute is meant for C ABI compatiblity, which is not + the same thing as binary compatibility across diverse platforms. + For that, use packed structs: + +

+
+

+	align (1) struct S
+	{   byte a;	// placed at offset 0
+	    byte[3] filler1;
+	    byte b;	// placed at offset 4
+	    byte[3] filler2;
+	}

+ + A value of 1 means that no alignment is done; + members are packed together. +

+ + Do not align references or pointers that were allocated + using NewExpression on boundaries that are not + a multipe of 4. The garbage collector assumes that pointers + and references to gc allocated objects will be on 4 + byte boundaries. If they are not, undefined behavior will + result. +

+ + AlignAttribute is ignored when applied to declarations + that are not structs or struct members. + +

Deprecated Attribute

+ + It is often necessary to deprecate a feature in a library, + yet retain it for backwards compatibility. Such + declarations can be marked as deprecated, which means + that the compiler can be set to produce an error + if any code refers to deprecated + declarations: + +

+
+

+	deprecated
+	{
+		void oldFoo();
+	}
+	

+ + Implementation Note: The compiler should have a switch + specifying if deprecated declarations should be compiled with + out complaint or not. + + +

Protection Attribute

+ + Protection is an attribute that is one of + private, package, protected, + public or export. +

+ + Private means that only members of the enclosing class can access + the member, or members and functions in the same module as the + enclosing class. + Private members cannot be overridden. + Private module members are equivalent to static declarations + in C programs. +

+ + Package extends private so that package members can be accessed + from code in other modules that are in the same package. + This applies to the innermost package only, if a module is in + nested packages. +

+ + Protected means that only members of the enclosing class or any + classes derived + from that class, or members and functions in the same module + as the enclosing class, can access the member. + Protected module members are illegal. +

+ + Public means that any code within the executable can access the member. +

+ + Export means that any code outside the executable can access the + member. Export + is analogous to exporting definitions from a DLL. + +

Const Attribute

+ +

+
+

+	const
+	

+ + The const attribute declares constants that can be + evaluated at compile time. For example: + +

+
+

+	const int foo = 7;
+
+	const
+	{
+	    double bar = foo + 6;
+	}
+	

+ +

Override Attribute

+ +

+
+

+	override
+	

+ + The override attribute applies to virtual functions. + It means that the function must override a function with the + same name and parameters in a base class. The override attribute + is useful for catching errors when a base class's member function + gets its parameters changed, and all derived classes need to have + their overriding functions updated. + +

+
+

+	class Foo
+	{
+	    int bar();
+	    int abc(int x);
+	}
+
+	class Foo2 : Foo
+	{
+	    override
+	    {
+		int bar(char c);	// error, no bar(char) in Foo
+		int abc(int x);		// ok
+	    }
+	}
+	

+ +

Static Attribute

+ +

+
+

+	static
+	

+ + The static attribute applies to functions and data. + It means that the declaration does not apply to a particular + instance of an object, but to the type of the object. In + other words, it means there is no this reference. + static is ignored when applied to other declarations. + +

+
+

+	class Foo
+	{
+	    static int bar() { return 6; }
+	    int foobar() { return 7; }
+	}
+
+	...
+
+	Foo f = new Foo;
+	Foo.bar();	// produces 6
+	Foo.foobar();	// error, no instance of Foo
+	f.bar();	// produces 6;
+	f.foobar();	// produces 7;
+	

+ + Static functions are never virtual. +

+ + Static data has only one instance for the entire program, + not once per object. +

+ + Static does not have the additional C meaning of being local + to a file. Use the private attribute in D to achieve that. + For example: + +

+
+

+	module foo;
+	int x = 3;		// x is global
+	private int y = 4;	// y is local to module foo
+	

+ + +

Auto Attribute

+ +

+
+

+	auto
+	

+ + The auto attribute is used for local variables and for class + declarations. For class declarations, the auto attribute creates + an auto class. + For local declarations, auto implements the RAII (Resource + Acquisition Is Initialization) protocol. This means that the + destructor for an object is automatically called when the auto + reference to it goes out of scope. The destructor is called even + if the scope is exited via a thrown exception, thus auto + is used to guarantee cleanup. +

+ + If there is more than one auto variable going out of scope + at the same point, then the destructors are called in the reverse + order that the variables were constructed. +

+ + Auto cannot be applied to globals, statics, data members, inout + or out parameters. Arrays of autos are not allowed, and auto + function return values are not allowed. Assignment to an auto, + other than initialization, is not allowed. + Rationale: These restrictions may get relaxed in the future + if a compelling reason to appears. + + +

Abstract Attribute

+ + If a class is abstract, it cannot be instantiated + directly. It can only be instantiated as a base class of + another, non-abstract, class. +

+ + Classes become abstract if they are defined within an + abstract attribute, or if any of the virtual member functions + within it are declared as abstract. +

+ + Non-virtual functions cannot be declared as abstract. +

+ + Functions declared as abstract can still have function + bodies. This is so that even though they must be overridden, + they can still provide 'base class functionality.' + + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/changelog.html dmd-0.124/dmd/html/d/changelog.html --- dmd-0.123/dmd/html/d/changelog.html 2005-05-11 14:55:44.000000000 +0200 +++ dmd-0.124/dmd/html/d/changelog.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,2106 +1,2160 @@ - - - - - -D Programming Language - Change Log - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -


- -

D Change Log

- - - - -
-

- What's New for - D 0.123 -

- -May 11, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.122 -

- -May 3, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.121 -

- -Apr 15, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.120 -

- -Apr 6, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.119 -

- -Mar 18, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.118 -

- -Mar 12, 2005 -

- -

Bugs Fixed

- - -
-

- What's New for - D 0.117 -

- -Mar 10, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.116 -

- -Mar 7, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.115 -

- -Feb 28, 2005 -

- -

Bugs Fixed

- - -
-

- What's New for - D 0.114 -

- -Feb 27, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.113 -

- -Feb 12, 2005 -

- -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.112 -

- -Jan 26, 2005 -

- -Note: This is a library only change, the dmd executables are still -at 0.111. - -

New/Changed Features

- - -
-

- What's New for - D 0.111 -

- -Jan 15, 2005 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.110 -

- -Dec 30, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.109 -

- -Dec 5, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.108 -

- -Nov 30, 2004 - -

Bugs Fixed

- - -
-

- What's New for - D 0.107 -

- -Nov 29, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.106 -

- -Nov 9, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.105 -

- -Oct 28, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

- What's New for - D 0.104 -

- -Oct 21, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.103

- -Oct 20, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.102

- -Sep 20, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.101

- -Aug 30, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.100

- -Aug 20, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.99

- -Aug 19, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.98

- -Aug 5, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.97

- -Jul 26, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.96

- -Jul 21, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.95

- -Jul 6, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.94

- -Jun 27, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.93

- -Jun 22, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.92

- -Jun 7, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.91

- -May 27, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.90

- -May 20, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.89

- -May 17, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.88

- -May 5, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.86

- -Apr 23, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.82

- -Mar 28, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.81

- -Mar 7, 2004 - -

Bugs Fixed

- - -
-

What's New for D 0.80

- -Mar 5, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.79

- -Feb 2, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.78

- -Jan 14, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.77

- -Jan 2, 2004 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.76

- -Nov 21, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.75

- -Nov 4, 2003 - -

New/Changed Features

- - -
-

What's New for D 0.74

- -Oct 15, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.73

- -Sep 18, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.72

- -Sep 14, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -

Linux Bugs Fixed

- - -
-

What's New for D 0.71

- -Sep 3, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.70

- -Aug 24, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.69

- -Aug 11, 2003 - -

New/Changed Features

- - -

Bugs Fixed

- - -
-

What's New for D 0.68

- -Jul 8, 2003 - - - -
-

What's New for D 0.67

- -Jun 17, 2003 - - - -
-

What's New for D 0.66

- -Jun 8, 2003 - - - -
-

What's New for D 0.65

- -May 13, 2003 - -

linux version

- - - -
-

What's New for D 0.64

- -May 12, 2003 - -

linux version

- - - -
-

What's New for D 0.63

- -May 10, 2003 - - - -
-

What's New for D 0.61

- -Mar 30, 2003 - - - -
-

What's New for D 0.59

- -Mar 6, 2003 - - - -
-

What's New for D 0.58

- -Mar 3, 2003 - - - -
-

What's New for D 0.57

- -Feb 25, 2003 - - - -Many thanks to Burton Radons for his help with this. - -
-

What's New for D 0.56

- -Feb 20, 2003 - - - -
-

What's New for D 0.55

- -Feb 17, 2003 - - - -
-

What's New for D 0.54

- -Feb 14, 2003 - - - - These changes have been needed for a while, and it's time to - put them in before D gets too constrained by legacy code. - Fortunately, using grep and global/search/replace can easily - take care of the type renames. - The array declaration issue can be fixed - by grepping for "][", and then manually fixing each. - - -
-

What's New for D 0.53

- -Feb 8, 2003 - - - - -
-

What's New for D 0.52

- -Feb 5, 2003 - - - - -
-

What's New for D 0.51

- -Jan 27, 2003 - - - - -
-

What's New for D 0.50

- -Nov 20, 2002 - - - - -
-

What's New for D 0.49

- -Nov 18, 2002 - - - - -
-

What's New for D 0.48

- -Oct 25, 2002 - - - - -
-

What's New for D 0.46

- -Oct 22, 2002 - - - - -
-

What's New for D 0.45

- -Oct 8, 2002 - - - - -
-

What's New for D 0.44

- -Oct 1, 2002 - - - - -
-

What's New for D 0.43

- -Sep 28, 2002 - - - - -
- -

Feedback and Comments

- - Add feedback and comments regarding this - page. - - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Change Log + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

D Change Log

+ + + + +
+

+ What's New for + D 0.124 +

+ +May 19, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.123 +

+ +May 11, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.122 +

+ +May 3, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.121 +

+ +Apr 15, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.120 +

+ +Apr 6, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.119 +

+ +Mar 18, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.118 +

+ +Mar 12, 2005 +

+ +

Bugs Fixed

+ + +
+

+ What's New for + D 0.117 +

+ +Mar 10, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.116 +

+ +Mar 7, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.115 +

+ +Feb 28, 2005 +

+ +

Bugs Fixed

+ + +
+

+ What's New for + D 0.114 +

+ +Feb 27, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.113 +

+ +Feb 12, 2005 +

+ +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.112 +

+ +Jan 26, 2005 +

+ +Note: This is a library only change, the dmd executables are still +at 0.111. + +

New/Changed Features

+ + +
+

+ What's New for + D 0.111 +

+ +Jan 15, 2005 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.110 +

+ +Dec 30, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.109 +

+ +Dec 5, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.108 +

+ +Nov 30, 2004 + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.107 +

+ +Nov 29, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.106 +

+ +Nov 9, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.105 +

+ +Oct 28, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

+ What's New for + D 0.104 +

+ +Oct 21, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.103

+ +Oct 20, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.102

+ +Sep 20, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.101

+ +Aug 30, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.100

+ +Aug 20, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.99

+ +Aug 19, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.98

+ +Aug 5, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.97

+ +Jul 26, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.96

+ +Jul 21, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.95

+ +Jul 6, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.94

+ +Jun 27, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.93

+ +Jun 22, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.92

+ +Jun 7, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.91

+ +May 27, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.90

+ +May 20, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.89

+ +May 17, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.88

+ +May 5, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.86

+ +Apr 23, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.82

+ +Mar 28, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.81

+ +Mar 7, 2004 + +

Bugs Fixed

+ + +
+

What's New for D 0.80

+ +Mar 5, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.79

+ +Feb 2, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.78

+ +Jan 14, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.77

+ +Jan 2, 2004 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.76

+ +Nov 21, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.75

+ +Nov 4, 2003 + +

New/Changed Features

+ + +
+

What's New for D 0.74

+ +Oct 15, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.73

+ +Sep 18, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.72

+ +Sep 14, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +

Linux Bugs Fixed

+ + +
+

What's New for D 0.71

+ +Sep 3, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.70

+ +Aug 24, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.69

+ +Aug 11, 2003 + +

New/Changed Features

+ + +

Bugs Fixed

+ + +
+

What's New for D 0.68

+ +Jul 8, 2003 + + + +
+

What's New for D 0.67

+ +Jun 17, 2003 + + + +
+

What's New for D 0.66

+ +Jun 8, 2003 + + + +
+

What's New for D 0.65

+ +May 13, 2003 + +

linux version

+ + + +
+

What's New for D 0.64

+ +May 12, 2003 + +

linux version

+ + + +
+

What's New for D 0.63

+ +May 10, 2003 + + + +
+

What's New for D 0.61

+ +Mar 30, 2003 + + + +
+

What's New for D 0.59

+ +Mar 6, 2003 + + + +
+

What's New for D 0.58

+ +Mar 3, 2003 + + + +
+

What's New for D 0.57

+ +Feb 25, 2003 + + + +Many thanks to Burton Radons for his help with this. + +
+

What's New for D 0.56

+ +Feb 20, 2003 + + + +
+

What's New for D 0.55

+ +Feb 17, 2003 + + + +
+

What's New for D 0.54

+ +Feb 14, 2003 + + + + These changes have been needed for a while, and it's time to + put them in before D gets too constrained by legacy code. + Fortunately, using grep and global/search/replace can easily + take care of the type renames. + The array declaration issue can be fixed + by grepping for "][", and then manually fixing each. + + +
+

What's New for D 0.53

+ +Feb 8, 2003 + + + + +
+

What's New for D 0.52

+ +Feb 5, 2003 + + + + +
+

What's New for D 0.51

+ +Jan 27, 2003 + + + + +
+

What's New for D 0.50

+ +Nov 20, 2002 + + + + +
+

What's New for D 0.49

+ +Nov 18, 2002 + + + + +
+

What's New for D 0.48

+ +Oct 25, 2002 + + + + +
+

What's New for D 0.46

+ +Oct 22, 2002 + + + + +
+

What's New for D 0.45

+ +Oct 8, 2002 + + + + +
+

What's New for D 0.44

+ +Oct 1, 2002 + + + + +
+

What's New for D 0.43

+ +Sep 28, 2002 + + + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/class.html dmd-0.124/dmd/html/d/class.html --- dmd-0.123/dmd/html/d/class.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/class.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,936 +1,973 @@ - - - - - -Digital Mars - The D Programming Language - Classes - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Mar 15, 2005 -


- -

Classes

- - The object-oriented features of D all come from classes. The class hierarchy - has as its root the class Object. Object defines a minimum level of functionality - that each derived class has, and a default implementation for that functionality. -

- - Classes are programmer defined types. Support for classes are what - make D an object oriented language, giving it encapsulation, inheritance, - and polymorphism. D classes support the single inheritance paradigm, extended - by adding support for interfaces. Class objects are instantiated by reference - only. -

- - A class can be exported, which means its name and all its non-private - members are exposed externally to the DLL or EXE. -

- - A class declaration is defined: - -

-	ClassDeclaration:
-		class Identifier [SuperClass {, InterfaceClass }] ClassBody
-
-	SuperClass:
-		: Identifier
-
-	InterfaceClass:
-		Identifier
-
-	ClassBody:
-		{ }
-		{ ClassBodyDeclarations }
-
-	ClassBodyDeclarations:
-		ClassBodyDeclaration
-		ClassBodyDeclaration ClassBodyDeclarations
-
-	ClassBodyDeclaration:
-		Declaration
-		Constructor
-		Destructor
-		StaticConstructor
-		StaticDestructor
-		Invariant
-		UnitTest
-		ClassAllocator
-		ClassDeallocator
-	
- -Classes consist of: - -
-
super class -
interfaces -
dynamic fields -
static fields -
types -
functions -
-
-
static functions -
dynamic functions -
constructors -
destructors -
static constructors -
static destructors -
invariants -
unit tests -
allocators -
deallocators -
-
-
- -A class is defined: - -
-	class Foo
-	{
-	    ... members ...
-	}
-
- -Note that there is no trailing ; after the closing } of the class definition. -It is also not possible to declare a variable var like: - -
-	class Foo { } var;
-
- -Instead: - -
-	class Foo { }
-	Foo var;
-
- -

Fields

- - Class members are always accessed with the . operator. There are no :: or -> - operators as in C++. -

- - The D compiler is free to rearrange the order of fields in a class to - optimally pack them in an implementation-defined manner. - Consider the fields much like the local - variables in a function - - the compiler assigns some to registers and shuffles others around all to - get the optimal - stack frame layout. This frees the code designer to organize the fields - in a manner that - makes the code more readable rather than being forced to organize it - according to - machine optimization rules. Explicit control of field layout is provided - by struct/union - types, not classes. - -

Field Properties

- -
-	.offsetof		Offset in bytes of field from beginning
-				of class
-
- -

Super Class

- - All classes inherit from a super class. If one is not specified, - it inherits from Object. Object forms the root of the D class - inheritance hierarchy. - -

Constructors

- -
-	Constructor:
-		this() BlockStatement
-	
- - Members are always initialized to the default initializer - for their type, which is usually 0 for integer types and - NAN for floating point types. - This eliminates an entire - class of obscure problems that come from - neglecting to initialize a member in one of the constructors. - In the class definition, - there can be a static initializer to be - used instead of the default: - -
-	class Abc
-	{
-	    int a;	// default initializer for a is 0
-	    long b = 7;	// default initializer for b is 7
-	    float f;	// default initializer for f is NAN
-	}
-	
- - This static initialization is done before any constructors are - called. -

- - Constructors are defined with a function name of this - and having no return value: - -

-	class Foo
-	{
-	    this(int x)		// declare constructor for Foo
-	    {   ...
-	    }
-	    this()
-	    {   ...
-	    }
-	}
-	
- - Base class construction is done by calling the base class - constructor by the name super: - -
-	class A { this(int y) { } }
-
-	class B : A
-	{
-	    int j;
-	    this()
-	    {
-		...
-		super(3);	// call base constructor A.this(3)
-		...
-	    }
-	}
-	
- - Constructors can also call other constructors for the same class - in order to share common initializations: - -
-	class C
-	{
-	    int j;
-	    this()
-	    {
-		...
-	    }
-	    this(int i)
-	    {
-		this();
-		j = i;
-	    }
-	}
-	
- - If no call to constructors via this or super appear - in a constructor, and the base class has a constructor, a call - to super() is inserted at the beginning of the constructor. -

- - If there is no constructor for a class, but there is a constructor - for the base class, a default constructor of the form: - -

-	this() { }
-	
- - is implicitly generated. -

- - Class object construction is very flexible, but some restrictions - apply: -

    -
  1. It is illegal for constructors to mutually call each other: -
    -	this() { this(1); }
    -	this(int i) { this(); }	// illegal, cyclic constructor calls
    -	
    -
  2. If any constructor call appears inside a constructor, any - path through the constructor must make exactly one constructor - call: -
    -	this()	{ a || super(); }	// illegal
    -
    -	this() { this(1) || super(); }	// ok
    -
    -	this()
    -	{
    -	    for (...)
    -	    {
    -		super();	// illegal, inside loop
    -	    }
    -	}
    -	
    -
  3. It is illegal to refer to this implicitly or explicitly - prior to making a constructor call. -
  4. Constructor calls cannot appear after labels (in order to make - it easy to check for the previous conditions in the presence of goto's). -
- - Instances of class objects are created with NewExpressions: - -
-	A a = new A(3);
-	
- - The following steps happen: - -
    -
  1. Storage is allocated for the object. - If this fails, rather than return null, an - OutOfMemoryException is thrown. - Thus, tedious checks for null references are unnecessary. - -
  2. The raw data is statically initialized using the values provided - in the class definition. - The pointer to the vtbl is assigned. - This ensures that constructors are - passed fully formed objects. - This operation is equivalent to doing a memcpy() of a static - version of the object onto the newly allocated one, - although more advanced compilers - may be able to optimize much of this away. - -
  3. If there is a constructor defined for the class, - the constructor matching the - argument list is called. - -
  4. If class invariant checking is turned on, the class invariant - is called at the end of the constructor. -
- -

Destructors

- -
-	Destructor:
-		~this() BlockStatement
-	
- - The garbage collector calls the destructor function when the object - is deleted. The syntax - is: - -
-	class Foo
-	{
-		~this()		// destructor for Foo
-		{
-		}
-	}
-	
- - There can be only one destructor per class, the destructor - does not have any parameters, - and has no attributes. It is always virtual. -

- - The destructor is expected to release any resources held by the object. -

- - The program can explicitly inform the garbage collector that an - object is no longer referred to (with the delete expression), and - then the garbage collector calls the destructor - immediately, and adds the object's memory to the free storage. - The destructor is guaranteed to never be called twice. -

- - The destructor for the super class automatically gets called when - the destructor ends. There is no way to call the super destructor - explicitly. -

- - When the garbage collector calls a destructor for an object of a class - that has - members that are references to garbage collected objects, those - references are no longer valid. This means that destructors - cannot reference sub objects. - This rule does not apply to auto objects or objects deleted - with the DeleteExpression. -

- - The garbage collector is not guaranteed to run the destructor - for all unreferenced objects. Furthermore, the order in which the - garbage collector calls destructors for unreference objects - is not specified. -

- - Objects referenced from the data segment never get collected - by the gc. - -

Static Constructors

- -
-	StaticConstructor:
-		static this() BlockStatement
-	
- - A static constructor is defined as a function that performs - initializations before the - main() function gets control. Static constructors are used to initialize - static class members - with values that cannot be computed at compile time. -

- - Static constructors in other languages are built implicitly by using - member - initializers that can't be computed at compile time. The trouble with - this stems from not - having good control over exactly when the code is executed, for example: - -

-	class Foo
-	{
-	    static int a = b + 1;
-	    static int b = a * 2;
-	}
-	
- - What values do a and b end up with, what order are the initializations - executed in, what - are the values of a and b before the initializations are run, is this a - compile error, or is this - a runtime error? Additional confusion comes from it not being obvious if - an initializer is - static or dynamic. -

- - D makes this simple. All member initializations must be determinable by - the compiler at - compile time, hence there is no order-of-evaluation dependency for - member - initializations, and it is not possible to read a value that has not - been initialized. Dynamic - initialization is performed by a static constructor, defined with - a special syntax static this(). - -

-	class Foo
-	{
-	    static int a;		// default initialized to 0
-	    static int b = 1;
-	    static int c = b + a;	// error, not a constant initializer
-
-	    static this()		// static constructor
-	    {
-		a = b + 1;		// a is set to 2
-		b = a * 2;		// b is set to 4
-	    }
-	}
-	
- - static this() is called by the startup code before - main() is called. If it returns normally - (does not throw an exception), the static destructor is added - to the list of functions to be - called on program termination. - Static constructors have empty parameter lists. -

- - Static constructors within a module are executed in the lexical - order in which they appear. - All the static constructors for modules that are directly or - indirectly imported - are executed before the static constructors for the importer. -

- - The static in the static constructor declaration is not - an attribute, it must appear immediately before the this: - -

-	class Foo
-	{
-	    static this() { ... }	// a static constructor
-	    static private this() { ... } // not a static constructor
-	    static
-	    {
-		this() { ... }		// not a static constructor
-	    }
-	    static:
-		this() { ... }		// not a static constructor
-	}
- -

Static Destructor

- -
-	StaticDestructor:
-		static ~this() BlockStatement
-	
- - A static destructor is defined as a special static function with the - syntax static ~this(). - -
-	class Foo
-	{
-	    static ~this()		// static destructor
-	    {
-	    }
-	}
- - A static destructor gets called on program termination, but only if - the static constructor - completed successfully. - Static destructors have empty parameter lists. - Static destructors get called in the reverse order that the static - constructors were called in. -

- - The static in the static denstructor declaration is not - an attribute, it must appear immediately before the ~this: - -

-	class Foo
-	{
-	    static ~this() { ... }	// a static destructor
-	    static private ~this() { ... } // not a static destructor
-	    static
-	    {
-		~this() { ... }		// not a static destructor
-	    }
-	    static:
-		~this() { ... }		// not a static destructor
-	}
- -

Class Invariants

- -
-	ClassInvariant:
-		invariant BlockStatement
-	
- - Class invariants are used to specify characteristics of a class that always - must be true (except while executing a member function). For example, a - class representing a date might have an invariant that the day must be 1..31 - and the hour must be 0..23: - - - -
-    class Date
-    {
-	int day;
-	int hour;
-
-	invariant
-	{
-	    assert(1 <= day && day <= 31);
-	    assert(0 <= hour && hour < 24);
-	}
-    }
-
- The class invariant is a contract saying that the asserts must hold - true. - The invariant is checked when a class constructor completes, - at the start of the class destructor, before a public or exported - member is run, and after a public or exported function finishes. -

- - The code in the invariant may not call any public non-static members - of the - class, either directly or indirectly. - Doing so will result in a stack overflow, as the invariant will wind - up being called in an infinitely recursive manner. - -

-    class Foo
-    {
-	public void f() { }
-	private void g() { }
-
-	invariant
-	{
-	    f();  // error, cannot call public member function from invariant
-	    g();  // ok, g() is not public
-	}
-    }
-
- - The invariant - can be checked when a class object is the argument to an - assert() expression, as: -
-	Date mydate;
-	...
-	assert(mydate);		// check that class Date invariant holds
-
- If the invariant fails, it throws an InvariantException. - Class invariants are inherited, that is, - any class invariant is implicitly anded with the invariants of its base classes. -

- There can be only one ClassInvariant per class. -

- When compiling for release, the invariant code is not generated, and the compiled program - runs at maximum speed. - -

Unit Tests

- -
-	UnitTest:
-		unittest BlockStatement
-	
- - Unit tests are a series of test cases applied to a class to determine - if it is working properly. Ideally, unit tests should be run every - time a program is compiled. The best way to make sure that unit - tests do get run, and that they are maintained along with the class - code is to put the test code right in with the class implementation - code. -

- - D classes can have a special member function called: - -

-	unittest
-	{
-	    ...test code...
-	}
-	
- - The test() functions for all the classes in the program get called - after static initialization is done and before the main function - is called. A compiler or linker switch will remove the test code - from the final build. -

- - For example, given a class Sum that is used to add two values: - -

-	class Sum
-	{
-	    int add(int x, int y) { return x + y; }
-
-	    unittest
-	    {
-		assert(add(3,4) == 7);
-		assert(add(-2,0) == -2);
-	    }
-	}
-	
- -

Class Allocators

- -
-	ClassAllocator:
-		new ParameterList BlockStatement
-	
- - A class member function of the form: - -
-	new(uint size)
-	{
-	    ...
-	}
-	
- - is called a class allocator. - The class allocator can have any number of parameters, provided - the first one is of type uint. - Any number can be defined for a class, the correct one is - determined by the usual function overloading rules. - When a new expression: - -
-	new Foo;
-	
- - is executed, and Foo is a class that has - an allocator, the allocator is called with the first argument - set to the size in bytes of the memory to be allocated for the - instance. - The allocator must allocate the memory and return it as a - void*. - If the allocator fails, it must not return a null, but - must throw an exception. - If there is more than one parameter to the allocator, the - additional arguments are specified within parentheses after - the new in the NewExpression: - -
-	class Foo
-	{
-	    this(char[] a) { ... }
-
-	    new(uint size, int x, int y)
-	    {
-		...
-	    }
-	}
-
-	...
-
-	new(1,2) Foo(a);	// calls new(Foo.size,1,2)
-	
- - Derived classes inherit any allocator from their base class, - if one is not specified. -

- - See also Explicit Class Instance Allocation. - -

Class Deallocators

- -
-	ClassDeallocator:
-		delete ParameterList BlockStatement
-	
- - A class member function of the form: - -
-	delete(void *p)
-	{
-	    ...
-	}
-	
- - is called a class deallocator. - The deallocator must have exactly one parameter of type void*. - Only one can be specified for a class. - When a delete expression: - -
-	delete f;
-	
- - is executed, and f is a reference to a class instance that has - a deallocator, the deallocator is called with a pointer to the - class instance after the destructor (if any) for the class is - called. It is the responsibility of the deallocator to free - the memory. -

- - Derived classes inherit any deallocator from their base class, - if one is not specified. -

- - See also Explicit Class Instance Allocation. - -

Auto Classes

- - An auto class is a class with the auto attribute, as in: - -
-	auto class Foo { ... }
-	
- - The auto characteristic is inherited, so if any classes derived - from an auto class are also auto. -

- - An auto class reference can only appear as a function local variable. - It must be declared as being auto: - -

-	auto class Foo { ... }
-
-	void func()
-	{
-	    Foo f;	// error, reference to auto class must be auto
-	    auto Foo g = new Foo();	// correct
-	}
-	
- - When an auto class reference goes out of scope, the destructor - (if any) for it is automatically called. This holds true even if - the scope was exited via a thrown exception. - -
-

Interfaces

- -
-	InterfaceDeclaration:
-		interface Identifier InterfaceBody
-		interface Identifier : SuperInterfaces InterfaceBody
-
-	SuperInterfaces
-		Identifier
-		Identifier , SuperInterfaces
-
-	InterfaceBody:
-		{ DeclDefs }
-	
- - Interfaces describe a list of functions that a class that inherits - from the interface must implement. - A class that implements an interface can be converted to a reference - to that interface. Interfaces correspond to the interface exposed - by operating system objects, like COM/OLE/ActiveX for Win32. -

- - Interfaces cannot derive from classes; only from other interfaces. - Classes cannot derive from an interface multiple times. - -

-	interface D
-	{
-	    void foo();
-	}
-
-	class A : D, D	// error, duplicate interface
-	{
-	}
-	
- - An instance of an interface cannot be created. - - -
-	interface D
-	{
-	    void foo();
-	}
-
-	...
-
-	D d = new D();		// error, cannot create instance of interface
-	
- - Interface member functions do not have implementations. - -
-	interface D
-	{
-	    void bar() { }	// error, implementation not allowed
-	}
-	
- - All interface functions must be defined in a class that inherits - from that interface: - -
-	interface D
-	{
-	    void foo();
-	}
-
-	class A : D
-	{
-	    void foo() { }	// ok, provides implementation
-	}
-
-	class B : D
-	{
-	    int foo() { }	// error, no void foo() implementation
-	}
-	
- - Interfaces can be inherited and functions overridden: - -
-	interface D
-	{
-	    int foo();
-	}
-
-	class A : D
-	{
-	    int foo() { return 1; }
-	}
-
-	class B : A
-	{
-	    int foo() { return 2; }
-	}
-
-	...
-
-	B b = new B();
-	b.foo();		// returns 2
-	D d = (D) b;		// ok since B inherits A's D implementation
-	d.foo();		// returns 2;
-	
- - Interfaces can be reimplemented in derived classes: - -
-	interface D
-	{
-	    int foo();
-	}
-
-	class A : D
-	{
-	    int foo() { return 1; }
-	}
-
-	class B : A, D
-	{
-	    int foo() { return 2; }
-	}
-
-	...
-
-	B b = new B();
-	b.foo();		// returns 2
-	D d = (D) b;
-	d.foo();		// returns 2
-	A a = (A) b;
-	D d2 = (D) a;
-	d2.foo();		// returns 2, even though it is A's D, not B's D
-	
- - A reimplemented interface must implement all the interface - functions, it does not inherit them from a super class: - -
-	interface D
-	{
-	    int foo();
-	}
-
-	class A : D
-	{
-	    int foo() { return 1; }
-	}
-
-	class B : A, D
-	{
-	}		// error, no foo() for interface D
-	
- -

COM Interfaces

- - A variant on interfaces is the COM interface. A COM interface is - designed to map directly onto a Windows COM object. Any COM object - can be represented by a COM interface, and any D object with - a COM interface can be used by external COM clients. -

- - A COM interface is defined as one that derives from the interface - std.c.windows.com.IUnknown. A COM interface differs from - a regular D interface in that: - -

- -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Classes + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

Classes

+ + The object-oriented features of D all come from classes. The class hierarchy + has as its root the class Object. Object defines a minimum level of functionality + that each derived class has, and a default implementation for that functionality. +

+ + Classes are programmer defined types. Support for classes are what + make D an object oriented language, giving it encapsulation, inheritance, + and polymorphism. D classes support the single inheritance paradigm, extended + by adding support for interfaces. Class objects are instantiated by reference + only. +

+ + A class can be exported, which means its name and all its non-private + members are exposed externally to the DLL or EXE. +

+ + A class declaration is defined: + +

+	ClassDeclaration:
+		class Identifier [SuperClass {, InterfaceClass }] ClassBody
+
+	SuperClass:
+		: Identifier
+
+	InterfaceClass:
+		Identifier
+
+	ClassBody:
+		{ }
+		{ ClassBodyDeclarations }
+
+	ClassBodyDeclarations:
+		ClassBodyDeclaration
+		ClassBodyDeclaration ClassBodyDeclarations
+
+	ClassBodyDeclaration:
+		Declaration
+		Constructor
+		Destructor
+		StaticConstructor
+		StaticDestructor
+		Invariant
+		UnitTest
+		ClassAllocator
+		ClassDeallocator
+	
+ +Classes consist of: + +
+
super class +
interfaces +
dynamic fields +
static fields +
types +
functions +
+
+
static functions +
dynamic functions +
constructors +
destructors +
static constructors +
static destructors +
invariants +
unit tests +
allocators +
deallocators +
+
+
+ +A class is defined: + +
+	class Foo
+	{
+	    ... members ...
+	}
+
+ +Note that there is no trailing ; after the closing } of the class definition. +It is also not possible to declare a variable var like: + +
+	class Foo { } var;
+
+ +Instead: + +
+	class Foo { }
+	Foo var;
+
+ +

Fields

+ + Class members are always accessed with the . operator. There are no :: or -> + operators as in C++. +

+ + The D compiler is free to rearrange the order of fields in a class to + optimally pack them in an implementation-defined manner. + Consider the fields much like the local + variables in a function - + the compiler assigns some to registers and shuffles others around all to + get the optimal + stack frame layout. This frees the code designer to organize the fields + in a manner that + makes the code more readable rather than being forced to organize it + according to + machine optimization rules. Explicit control of field layout is provided + by struct/union + types, not classes. + +

Field Properties

+ + The .offsetof property gives the offset in bytes of the field + from the beginning of the class instantiation. + .offsetof can only be applied to fields qualified with the + type of the class, not expressions which produce the type of + the field itself: +
+	class Foo
+	{
+	    int x;
+	}
+	...
+	void test(Foo foo)
+	{
+	    size_t o;
+
+	    o = Foo.x.offsetof;   // yields 8
+	    o = foo.x.offsetof;   // error, .offsetof an int type
+	}
+
+ +

Super Class

+ + All classes inherit from a super class. If one is not specified, + it inherits from Object. Object forms the root of the D class + inheritance hierarchy. + +

Constructors

+ +
+	Constructor:
+		this() BlockStatement
+	
+ + Members are always initialized to the default initializer + for their type, which is usually 0 for integer types and + NAN for floating point types. + This eliminates an entire + class of obscure problems that come from + neglecting to initialize a member in one of the constructors. + In the class definition, + there can be a static initializer to be + used instead of the default: + +
+	class Abc
+	{
+	    int a;	// default initializer for a is 0
+	    long b = 7;	// default initializer for b is 7
+	    float f;	// default initializer for f is NAN
+	}
+	
+ + This static initialization is done before any constructors are + called. +

+ + Constructors are defined with a function name of this + and having no return value: + +

+	class Foo
+	{
+	    this(int x)		// declare constructor for Foo
+	    {   ...
+	    }
+	    this()
+	    {   ...
+	    }
+	}
+	
+ + Base class construction is done by calling the base class + constructor by the name super: + +
+	class A { this(int y) { } }
+
+	class B : A
+	{
+	    int j;
+	    this()
+	    {
+		...
+		super(3);	// call base constructor A.this(3)
+		...
+	    }
+	}
+	
+ + Constructors can also call other constructors for the same class + in order to share common initializations: + +
+	class C
+	{
+	    int j;
+	    this()
+	    {
+		...
+	    }
+	    this(int i)
+	    {
+		this();
+		j = i;
+	    }
+	}
+	
+ + If no call to constructors via this or super appear + in a constructor, and the base class has a constructor, a call + to super() is inserted at the beginning of the constructor. +

+ + If there is no constructor for a class, but there is a constructor + for the base class, a default constructor of the form: + +

+	this() { }
+	
+ + is implicitly generated. +

+ + Class object construction is very flexible, but some restrictions + apply: +

    +
  1. It is illegal for constructors to mutually call each other: +
    +	this() { this(1); }
    +	this(int i) { this(); }	// illegal, cyclic constructor calls
    +	
    +
  2. If any constructor call appears inside a constructor, any + path through the constructor must make exactly one constructor + call: +
    +	this()	{ a || super(); }	// illegal
    +
    +	this() { this(1) || super(); }	// ok
    +
    +	this()
    +	{
    +	    for (...)
    +	    {
    +		super();	// illegal, inside loop
    +	    }
    +	}
    +	
    +
  3. It is illegal to refer to this implicitly or explicitly + prior to making a constructor call. +
  4. Constructor calls cannot appear after labels (in order to make + it easy to check for the previous conditions in the presence of goto's). +
+ + Instances of class objects are created with NewExpressions: + +
+	A a = new A(3);
+	
+ + The following steps happen: + +
    +
  1. Storage is allocated for the object. + If this fails, rather than return null, an + OutOfMemoryException is thrown. + Thus, tedious checks for null references are unnecessary. + +
  2. The raw data is statically initialized using the values provided + in the class definition. + The pointer to the vtbl is assigned. + This ensures that constructors are + passed fully formed objects. + This operation is equivalent to doing a memcpy() of a static + version of the object onto the newly allocated one, + although more advanced compilers + may be able to optimize much of this away. + +
  3. If there is a constructor defined for the class, + the constructor matching the + argument list is called. + +
  4. If class invariant checking is turned on, the class invariant + is called at the end of the constructor. +
+ +

Destructors

+ +
+	Destructor:
+		~this() BlockStatement
+	
+ + The garbage collector calls the destructor function when the object + is deleted. The syntax + is: + +
+	class Foo
+	{
+		~this()		// destructor for Foo
+		{
+		}
+	}
+	
+ + There can be only one destructor per class, the destructor + does not have any parameters, + and has no attributes. It is always virtual. +

+ + The destructor is expected to release any resources held by the object. +

+ + The program can explicitly inform the garbage collector that an + object is no longer referred to (with the delete expression), and + then the garbage collector calls the destructor + immediately, and adds the object's memory to the free storage. + The destructor is guaranteed to never be called twice. +

+ + The destructor for the super class automatically gets called when + the destructor ends. There is no way to call the super destructor + explicitly. +

+ + When the garbage collector calls a destructor for an object of a class + that has + members that are references to garbage collected objects, those + references are no longer valid. This means that destructors + cannot reference sub objects. + This rule does not apply to auto objects or objects deleted + with the DeleteExpression. +

+ + The garbage collector is not guaranteed to run the destructor + for all unreferenced objects. Furthermore, the order in which the + garbage collector calls destructors for unreference objects + is not specified. +

+ + Objects referenced from the data segment never get collected + by the gc. + +

Static Constructors

+ +
+	StaticConstructor:
+		static this() BlockStatement
+	
+ + A static constructor is defined as a function that performs + initializations before the + main() function gets control. Static constructors are used to initialize + static class members + with values that cannot be computed at compile time. +

+ + Static constructors in other languages are built implicitly by using + member + initializers that can't be computed at compile time. The trouble with + this stems from not + having good control over exactly when the code is executed, for example: + +

+	class Foo
+	{
+	    static int a = b + 1;
+	    static int b = a * 2;
+	}
+	
+ + What values do a and b end up with, what order are the initializations + executed in, what + are the values of a and b before the initializations are run, is this a + compile error, or is this + a runtime error? Additional confusion comes from it not being obvious if + an initializer is + static or dynamic. +

+ + D makes this simple. All member initializations must be determinable by + the compiler at + compile time, hence there is no order-of-evaluation dependency for + member + initializations, and it is not possible to read a value that has not + been initialized. Dynamic + initialization is performed by a static constructor, defined with + a special syntax static this(). + +

+	class Foo
+	{
+	    static int a;		// default initialized to 0
+	    static int b = 1;
+	    static int c = b + a;	// error, not a constant initializer
+
+	    static this()		// static constructor
+	    {
+		a = b + 1;		// a is set to 2
+		b = a * 2;		// b is set to 4
+	    }
+	}
+	
+ + static this() is called by the startup code before + main() is called. If it returns normally + (does not throw an exception), the static destructor is added + to the list of functions to be + called on program termination. + Static constructors have empty parameter lists. +

+ + Static constructors within a module are executed in the lexical + order in which they appear. + All the static constructors for modules that are directly or + indirectly imported + are executed before the static constructors for the importer. +

+ + The static in the static constructor declaration is not + an attribute, it must appear immediately before the this: + +

+	class Foo
+	{
+	    static this() { ... }	// a static constructor
+	    static private this() { ... } // not a static constructor
+	    static
+	    {
+		this() { ... }		// not a static constructor
+	    }
+	    static:
+		this() { ... }		// not a static constructor
+	}
+ +

Static Destructor

+ +
+	StaticDestructor:
+		static ~this() BlockStatement
+	
+ + A static destructor is defined as a special static function with the + syntax static ~this(). + +
+	class Foo
+	{
+	    static ~this()		// static destructor
+	    {
+	    }
+	}
+ + A static destructor gets called on program termination, but only if + the static constructor + completed successfully. + Static destructors have empty parameter lists. + Static destructors get called in the reverse order that the static + constructors were called in. +

+ + The static in the static denstructor declaration is not + an attribute, it must appear immediately before the ~this: + +

+	class Foo
+	{
+	    static ~this() { ... }	// a static destructor
+	    static private ~this() { ... } // not a static destructor
+	    static
+	    {
+		~this() { ... }		// not a static destructor
+	    }
+	    static:
+		~this() { ... }		// not a static destructor
+	}
+ +

Class Invariants

+ +
+	ClassInvariant:
+		invariant BlockStatement
+	
+ + Class invariants are used to specify characteristics of a class that always + must be true (except while executing a member function). For example, a + class representing a date might have an invariant that the day must be 1..31 + and the hour must be 0..23: + + + +
+    class Date
+    {
+	int day;
+	int hour;
+
+	invariant
+	{
+	    assert(1 <= day && day <= 31);
+	    assert(0 <= hour && hour < 24);
+	}
+    }
+
+ The class invariant is a contract saying that the asserts must hold + true. + The invariant is checked when a class constructor completes, + at the start of the class destructor, before a public or exported + member is run, and after a public or exported function finishes. +

+ + The code in the invariant may not call any public non-static members + of the + class, either directly or indirectly. + Doing so will result in a stack overflow, as the invariant will wind + up being called in an infinitely recursive manner. + +

+    class Foo
+    {
+	public void f() { }
+	private void g() { }
+
+	invariant
+	{
+	    f();  // error, cannot call public member function from invariant
+	    g();  // ok, g() is not public
+	}
+    }
+
+ + The invariant + can be checked when a class object is the argument to an + assert() expression, as: +
+	Date mydate;
+	...
+	assert(mydate);		// check that class Date invariant holds
+
+ If the invariant fails, it throws an InvariantException. + Class invariants are inherited, that is, + any class invariant is implicitly anded with the invariants of its base classes. +

+ There can be only one ClassInvariant per class. +

+ When compiling for release, the invariant code is not generated, and the compiled program + runs at maximum speed. + +

Unit Tests

+ +
+	UnitTest:
+		unittest BlockStatement
+	
+ + Unit tests are a series of test cases applied to a class to determine + if it is working properly. Ideally, unit tests should be run every + time a program is compiled. The best way to make sure that unit + tests do get run, and that they are maintained along with the class + code is to put the test code right in with the class implementation + code. +

+ + D classes can have a special member function called: + +

+	unittest
+	{
+	    ...test code...
+	}
+	
+ + The test() functions for all the classes in the program get called + after static initialization is done and before the main function + is called. A compiler or linker switch will remove the test code + from the final build. +

+ + For example, given a class Sum that is used to add two values: + +

+	class Sum
+	{
+	    int add(int x, int y) { return x + y; }
+
+	    unittest
+	    {
+		assert(add(3,4) == 7);
+		assert(add(-2,0) == -2);
+	    }
+	}
+	
+ +

Class Allocators

+ +
+	ClassAllocator:
+		new ParameterList BlockStatement
+	
+ + A class member function of the form: + +
+	new(uint size)
+	{
+	    ...
+	}
+	
+ + is called a class allocator. + The class allocator can have any number of parameters, provided + the first one is of type uint. + Any number can be defined for a class, the correct one is + determined by the usual function overloading rules. + When a new expression: + +
+	new Foo;
+	
+ + is executed, and Foo is a class that has + an allocator, the allocator is called with the first argument + set to the size in bytes of the memory to be allocated for the + instance. + The allocator must allocate the memory and return it as a + void*. + If the allocator fails, it must not return a null, but + must throw an exception. + If there is more than one parameter to the allocator, the + additional arguments are specified within parentheses after + the new in the NewExpression: + +
+	class Foo
+	{
+	    this(char[] a) { ... }
+
+	    new(uint size, int x, int y)
+	    {
+		...
+	    }
+	}
+
+	...
+
+	new(1,2) Foo(a);	// calls new(Foo.size,1,2)
+	
+ + Derived classes inherit any allocator from their base class, + if one is not specified. +

+ + See also Explicit Class Instance Allocation. + +

Class Deallocators

+ +
+	ClassDeallocator:
+		delete ParameterList BlockStatement
+	
+ + A class member function of the form: + +
+	delete(void *p)
+	{
+	    ...
+	}
+	
+ + is called a class deallocator. + The deallocator must have exactly one parameter of type void*. + Only one can be specified for a class. + When a delete expression: + +
+	delete f;
+	
+ + is executed, and f is a reference to a class instance that has + a deallocator, the deallocator is called with a pointer to the + class instance after the destructor (if any) for the class is + called. It is the responsibility of the deallocator to free + the memory. +

+ + Derived classes inherit any deallocator from their base class, + if one is not specified. +

+ + See also Explicit Class Instance Allocation. + +

Auto Classes

+ + An auto class is a class with the auto attribute, as in: + +
+	auto class Foo { ... }
+	
+ + The auto characteristic is inherited, so if any classes derived + from an auto class are also auto. +

+ + An auto class reference can only appear as a function local variable. + It must be declared as being auto: + +

+	auto class Foo { ... }
+
+	void func()
+	{
+	    Foo f;	// error, reference to auto class must be auto
+	    auto Foo g = new Foo();	// correct
+	}
+	
+ + When an auto class reference goes out of scope, the destructor + (if any) for it is automatically called. This holds true even if + the scope was exited via a thrown exception. + +
+

Interfaces

+ +
+	InterfaceDeclaration:
+		interface Identifier InterfaceBody
+		interface Identifier : SuperInterfaces InterfaceBody
+
+	SuperInterfaces
+		Identifier
+		Identifier , SuperInterfaces
+
+	InterfaceBody:
+		{ DeclDefs }
+	
+ + Interfaces describe a list of functions that a class that inherits + from the interface must implement. + A class that implements an interface can be converted to a reference + to that interface. Interfaces correspond to the interface exposed + by operating system objects, like COM/OLE/ActiveX for Win32. +

+ + Interfaces cannot derive from classes; only from other interfaces. + Classes cannot derive from an interface multiple times. + +

+	interface D
+	{
+	    void foo();
+	}
+
+	class A : D, D	// error, duplicate interface
+	{
+	}
+	
+ + An instance of an interface cannot be created. + + +
+	interface D
+	{
+	    void foo();
+	}
+
+	...
+
+	D d = new D();		// error, cannot create instance of interface
+	
+ + Interface member functions do not have implementations. + +
+	interface D
+	{
+	    void bar() { }	// error, implementation not allowed
+	}
+	
+ + All interface functions must be defined in a class that inherits + from that interface: + +
+	interface D
+	{
+	    void foo();
+	}
+
+	class A : D
+	{
+	    void foo() { }	// ok, provides implementation
+	}
+
+	class B : D
+	{
+	    int foo() { }	// error, no void foo() implementation
+	}
+	
+ + Interfaces can be inherited and functions overridden: + +
+	interface D
+	{
+	    int foo();
+	}
+
+	class A : D
+	{
+	    int foo() { return 1; }
+	}
+
+	class B : A
+	{
+	    int foo() { return 2; }
+	}
+
+	...
+
+	B b = new B();
+	b.foo();		// returns 2
+	D d = (D) b;		// ok since B inherits A's D implementation
+	d.foo();		// returns 2;
+	
+ + Interfaces can be reimplemented in derived classes: + +
+	interface D
+	{
+	    int foo();
+	}
+
+	class A : D
+	{
+	    int foo() { return 1; }
+	}
+
+	class B : A, D
+	{
+	    int foo() { return 2; }
+	}
+
+	...
+
+	B b = new B();
+	b.foo();		// returns 2
+	D d = (D) b;
+	d.foo();		// returns 2
+	A a = (A) b;
+	D d2 = (D) a;
+	d2.foo();		// returns 2, even though it is A's D, not B's D
+	
+ + A reimplemented interface must implement all the interface + functions, it does not inherit them from a super class: + +
+	interface D
+	{
+	    int foo();
+	}
+
+	class A : D
+	{
+	    int foo() { return 1; }
+	}
+
+	class B : A, D
+	{
+	}		// error, no foo() for interface D
+	
+ +

COM Interfaces

+ + A variant on interfaces is the COM interface. A COM interface is + designed to map directly onto a Windows COM object. Any COM object + can be represented by a COM interface, and any D object with + a COM interface can be used by external COM clients. +

+ + A COM interface is defined as one that derives from the interface + std.c.windows.com.IUnknown. A COM interface differs from + a regular D interface in that: + +

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/cppcomplex.html dmd-0.124/dmd/html/d/cppcomplex.html --- dmd-0.123/dmd/html/d/cppcomplex.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/cppcomplex.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,217 +1,272 @@ - - -D Programming Language - D Complex Types vs C++ std::complex - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Sep 1, 2003 -


- -

D Complex Types and C++ std::complex

- - How do D's complex numbers compare with C++'s std::complex class? - -

Syntactical Aesthetics

- - In C++, the complex types are: - -
-	complex<float>
-	complex<double>
-	complex<long double>
-	
- - C++ has no distinct imaginary type. D has 3 complex types and 3 - imaginary types: - -
-	cfloat
-	cdouble
-	creal
-	ifloat
-	idouble
-	ireal
-	
- - A C++ complex number can interact with an arithmetic literal, but - since there is no imaginary type, imaginary numbers can only be - created with the constructor syntax: - -
-	complex<long double> a = 5;		// a = 5 + 0i
-	complex<long double> b(0,7);		// b = 0 + 7i
-	c = a + b + complex<long double>(0,7);	// c = 5 + 14i
-	
- - In D, an imaginary numeric literal has the 'i' suffix. - The corresponding code would be the more natural: - -
-	creal a = 5;		// a = 5 + 0i
-	ireal b = 7i;		// b = 7i
-	c = a + b + 7i;		// c = 5 + 14i
-	
- - For more involved expressions involving constants: - -
-	c = (6 + 2i - 1 + 3i) / 3i;
-	
- - In C++, this would be: - -
-	c = (complex<double>(6,2) + complex<double>(-1,3)) / complex<double>(0,3);
-	
- - or if an imaginary class were added to C++ it might be: - -
-	c = (6 + imaginary<double>(2) - 1 + imaginary<double>(3))) / imaginary<double>(3);
-	
- - In other words, an imaginary number nn can be represented with - just nni rather than writing a constructor call - complex<long double>(0,nn). - -

Efficiency

- - The lack of an imaginary type in C++ means that operations on - imaginary numbers wind up with a lot of extra computations done - on the 0 real part. For example, adding two imaginary numbers - in D is one add: - -
-	ireal a, b, c;
-	c = a + b;
-	
- - In C++, it is two adds, as the real parts get added too: - -
-	c.re = a.re + b.re;
-	c.im = a.im + b.im;
-	
- - Multiply is worse, as 4 multiplies and two adds are done instead of - one multiply: - -
-	c.re = a.re * b.re - a.im * b.im;
-	c.im = a.im * b.re + a.re * b.im;
-	
- - Divide is the worst - D has one divide, whereas C++ implements - complex division with typically one comparison, 3 divides, - 3 multiplies and 3 additions: - -
-	if (fabs(b.re) < fabs(b.im))
-	{
-	    r = b.re / b.im;
-	    den = b.im + r * b.re;
-	    c.re = (a.re * r + a.im) / den;
-	    c.im = (a.im * r - a.re) / den;
-	}
-	else
-	{
-	    r = b.im / b.re;
-	    den = b.re + r * b.im;
-	    c.re = (a.re + r * a.im) / den;
-	    c.im = (a.im - r * a.re) / den;
-	}
-	
- - To avoid these efficiency concerns in C++, one could simulate - an imaginary number using a double. For example, given the D: - -
-	cdouble c;
-	idouble im;
-	c *= im;
-	
- - it could be written in C++ as: - -
-	complex<double> c;
-	double im;
-	c = complex<double>(-c.imag() * im, c.real() * im);
-	
- - but then the advantages of complex being a library type integrated - in with the arithmetic operators have been lost. - -

Semantics

- - Worst of all, the lack of an imaginary type can cause the wrong - answer to be inadvertently produced. - To quote - Prof. Kahan: - -
- "A streamline goes astray when the complex functions SQRT and LOG - are implemented, as is necessary in Fortran and in libraries - currently distributed with C/C++ compilers, in a way that - disregards the sign of 0.0 in IEEE 754 arithmetic and consequently - violates identities like SQRT( CONJ( Z ) ) = CONJ( SQRT( Z ) ) and - LOG( CONJ( Z ) ) = CONJ( LOG( Z ) ) whenever the COMPLEX variable Z - takes negative real values. Such anomalies are unavoidable if - Complex Arithmetic operates on pairs (x, y) instead of notional - sums x + i*y of real and imaginary - variables. The language of pairs is incorrect for Complex - Arithmetic; it needs the Imaginary type." -
- - The semantic problems are: - - - - Appendix G of the C99 standard has recommendations for dealing - with this problem. However, those recommendations are not part - of the C++98 standard, and so cannot be portably relied upon. - -

References

- - - How Java's Floating-Point Hurts Everyone Everywhere - Prof. W. Kahan and Joseph D. Darcy -

- - - The Numerical Analyst as Computer Science Curmudgeon - by Prof. W. Kahan -

- - "Branch Cuts for Complex Elementary Functions, - or Much Ado About Nothing's Sign Bit" - by W. Kahan, ch.
- 7 in The State of the Art in Numerical Analysis (1987) - ed. by M. Powell and A. Iserles for Oxford U.P. - - -

Feedback and Comments

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

- - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - D Complex Types vs C++ std::complex + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

D Complex Types and C++ std::complex

+ + How do D's complex numbers compare with C++'s std::complex class? + +

Syntactical Aesthetics

+ + In C++, the complex types are: + +

+
+

+	complex<float>
+	complex<double>
+	complex<long double>
+	

+ + C++ has no distinct imaginary type. D has 3 complex types and 3 + imaginary types: + +

+
+

+	cfloat
+	cdouble
+	creal
+	ifloat
+	idouble
+	ireal
+	

+ + A C++ complex number can interact with an arithmetic literal, but + since there is no imaginary type, imaginary numbers can only be + created with the constructor syntax: + +

+
+

+	complex<long double> a = 5;		// a = 5 + 0i
+	complex<long double> b(0,7);		// b = 0 + 7i
+	c = a + b + complex<long double>(0,7);	// c = 5 + 14i
+	

+ + In D, an imaginary numeric literal has the 'i' suffix. + The corresponding code would be the more natural: + +

+
+

+	creal a = 5;		// a = 5 + 0i
+	ireal b = 7i;		// b = 7i
+	c = a + b + 7i;		// c = 5 + 14i
+	

+ + For more involved expressions involving constants: + +

+
+

+	c = (6 + 2i - 1 + 3i) / 3i;
+	

+ + In C++, this would be: + +

+
+

+	c = (complex<double>(6,2) + complex<double>(-1,3)) / complex<double>(0,3);
+	

+ + or if an imaginary class were added to C++ it might be: + +

+
+

+	c = (6 + imaginary<double>(2) - 1 + imaginary<double>(3))) / imaginary<double>(3);
+	

+ + In other words, an imaginary number nn can be represented with + just nni rather than writing a constructor call + complex<long double>(0,nn). + +

Efficiency

+ + The lack of an imaginary type in C++ means that operations on + imaginary numbers wind up with a lot of extra computations done + on the 0 real part. For example, adding two imaginary numbers + in D is one add: + +

+
+

+	ireal a, b, c;
+	c = a + b;
+	

+ + In C++, it is two adds, as the real parts get added too: + +

+
+

+	c.re = a.re + b.re;
+	c.im = a.im + b.im;
+	

+ + Multiply is worse, as 4 multiplies and two adds are done instead of + one multiply: + +

+
+

+	c.re = a.re * b.re - a.im * b.im;
+	c.im = a.im * b.re + a.re * b.im;
+	

+ + Divide is the worst - D has one divide, whereas C++ implements + complex division with typically one comparison, 3 divides, + 3 multiplies and 3 additions: + +

+
+

+	if (fabs(b.re) < fabs(b.im))
+	{
+	    r = b.re / b.im;
+	    den = b.im + r * b.re;
+	    c.re = (a.re * r + a.im) / den;
+	    c.im = (a.im * r - a.re) / den;
+	}
+	else
+	{
+	    r = b.im / b.re;
+	    den = b.re + r * b.im;
+	    c.re = (a.re + r * a.im) / den;
+	    c.im = (a.im - r * a.re) / den;
+	}
+	

+ + To avoid these efficiency concerns in C++, one could simulate + an imaginary number using a double. For example, given the D: + +

+
+

+	cdouble c;
+	idouble im;
+	c *= im;
+	

+ + it could be written in C++ as: + +

+
+

+	complex<double> c;
+	double im;
+	c = complex<double>(-c.imag() * im, c.real() * im);
+	

+ + but then the advantages of complex being a library type integrated + in with the arithmetic operators have been lost. + +

Semantics

+ + Worst of all, the lack of an imaginary type can cause the wrong + answer to be inadvertently produced. + To quote + Prof. Kahan: + +
+ "A streamline goes astray when the complex functions SQRT and LOG + are implemented, as is necessary in Fortran and in libraries + currently distributed with C/C++ compilers, in a way that + disregards the sign of 0.0 in IEEE 754 arithmetic and consequently + violates identities like SQRT( CONJ( Z ) ) = CONJ( SQRT( Z ) ) and + LOG( CONJ( Z ) ) = CONJ( LOG( Z ) ) whenever the COMPLEX variable Z + takes negative real values. Such anomalies are unavoidable if + Complex Arithmetic operates on pairs (x, y) instead of notional + sums x + i*y of real and imaginary + variables. The language of pairs is incorrect for Complex + Arithmetic; it needs the Imaginary type." +
+ + The semantic problems are: + + + + Appendix G of the C99 standard has recommendations for dealing + with this problem. However, those recommendations are not part + of the C++98 standard, and so cannot be portably relied upon. + +

References

+ + + How Java's Floating-Point Hurts Everyone Everywhere + Prof. W. Kahan and Joseph D. Darcy +

+ + + The Numerical Analyst as Computer Science Curmudgeon + by Prof. W. Kahan +

+ + "Branch Cuts for Complex Elementary Functions, + or Much Ado About Nothing's Sign Bit" + by W. Kahan, ch.
+ 7 in The State of the Art in Numerical Analysis (1987) + ed. by M. Powell and A. Iserles for Oxford U.P. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/cppdbc.html dmd-0.124/dmd/html/d/cppdbc.html --- dmd-0.123/dmd/html/d/cppdbc.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/cppdbc.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,512 +1,568 @@ - - -D Programming Language - D's Contract Programming vs C++'s - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Sep 7, 2003 -


- -

D's Contract Programming vs C++'s

- - Many people have written me saying that D's Contract Programming - (DbC) does not add anything that C++ does not already support. - They go on to illustrate their point with a technique for doing DbC in - C++. -

- - It makes sense to review what DbC is, how it is done in D, - and stack that up with what each of the various C++ DbC techniques - can do. -

- - Digital Mars C++ adds - extensions to C++ - to support DbC, but they are not covered here because they are not - part of standard C++ and are not supported by any other C++ compiler. - -

Contract Programming in D

- - This is more fully documented in the D - Contract Programming document. - To sum up, DbC in D has the following characteristics: - -
    - -
  1. The assert is the basic contract. - -
  2. When an assert contract fails, it throws an exception. - Such exceptions can be caught and handled, or allowed to - terminate the program. - -
  3. Classes can have class invariants which are - checked upon entry and exit of each public class member function, - the exit of each constructor, and the entry of the destructor. - -
  4. Assert contracts on object references check the class - invariant for that object. - -
  5. Class invariants are inherited, that means that a derived - class invariant will implicitly call the base class invariant. - -
  6. Functions can have preconditions and postconditions. - -
  7. For member functions in a class inheritance hierarchy, the - precondition of a derived class function are OR'd together - with the preconditions of all the functions it overrides. - The postconditions are AND'd together. - -
  8. By throwing a compiler switch, DbC code can be enabled - or can be withdrawn from the compiled code. - -
  9. Code works semantically the same with or without DbC - checking enabled. - -
- -

Contract Programming in C++

- -

The assert Macro

- - C++ does have the basic assert macro, which tests its argument - and if it fails, aborts the program. assert can be turned - on and off with the NDEBUG macro. -

- - assert does not know anything about class invariants, - and does not throw an exception when it fails. It just aborts - the program after writing a message. assert relies on - a macro text preprocessor to work. -

- - assert is where explicit support for DbC in Standard C++ - begins and ends. - -

Class Invariants

- - Consider a class invariant in D: - -
-	class A
-	{
-	    invariant() { ...contracts... }
-
-	    this() { ... }	// constructor
-	    ~this() { ... }	// destructor
-
-	    void foo() { ... }	// public member function
-	}
-
-	class B : A
-	{
-	    invariant() { ...contracts... }
-	    ...
-	}
-	
- - To accomplish the equivalent in C++ (thanks to Bob Bell for providing - this): - -
-	template
-	inline void check_invariant(T& iX)
-	{
-	#ifdef DBC
-	    iX.invariant();
-	#endif
-	}
-
-	// A.h:
-
-	class A {
-	    public:
-	#ifdef DBG
-	       virtual void invariant() { ...contracts... }
-	#endif
-	       void foo();
-	};
-
-	// A.cpp:
-
-	void A::foo()
-	{
-	    check_invariant(*this);
-	    ...
-	    check_invariant(*this);
-	}
-
-	// B.h:
-
-	#include "A.h"
-
-	class B : public A {
-	    public:
-	#ifdef DBG
-		virtual void invariant()
-		{ ...contracts...
-		   A::invariant();
-		}
-	#endif
-	       void bar();
-	};
-
-	// B.cpp:
-
-	void B::barG()
-	{
-	    check_invariant(*this);
-	    ...
-	    check_invariant(*this);
-	}
-	
- - There's an additional complication with A::foo(). Upon every - normal exit from the function, the invariant() should be - called. - This means that code that looks like: - -
-	int A::foo()
-	{
-	    ...
-	    if (...)
-		return bar();
-	    return 3;
-	}
-	
- - would need to be written as: - -
-	int A::foo()
-	{
-	    int result;
-	    check_invariant(*this);
-	    ...
-	    if (...)
-	    {
-		result = bar();
-		check_invariant(*this);
-		return result;
-	    }
-	    check_invariant(*this);
-	    return 3;
-	}
-	
- - Or recode the function so it has a single exit point. - One possibility to mitigate this is to use RAII techniques: - -
-	int A::foo()
-	{
-	#if DBC
-	    struct Sentry {
-	       Sentry(A& iA) : mA(iA) { check_invariants(iA); }
-	       ~Sentry() { check_invariants(mA); }
-	       A& mA;
-	    } sentry(*this);
-	#endif
-	    ...
-	    if (...)
-		return bar();
-	    return 3;
-	}
-	
- - The #if DBC is still there because some compilers may not - optimize the whole thing away if check_invariants compiles to nothing. - -

Preconditions and Postconditions

- - Consider the following in D: - -
-	void foo()
-	    in { ...preconditions... }
-	    out { ...postconditions... }
-	    body
-	    {
-		...implementation...
-	    }
-	
- - This is nicely handled in C++ with the nested Sentry struct: - -
-	void foo()
-	{
-	    struct Sentry
-	    {	Sentry() { ...preconditions... }
-		~Sentry() { ...postconditions... }
-	    } sentry;
-	    ...implementation...
-	}
-	
- - If the preconditions and postconditions consist of nothing - more than assert macros, the whole doesn't need to - be wrapped in a #ifdef pair, since a good C++ compiler will - optimize the whole thing away if the asserts are turned off. -

- - But suppose foo() sorts an array, and the postcondition needs - to walk the array and verify that it really is sorted. Now - the shebang needs to be wrapped in #ifdef: - -

-	void foo()
-	{
-	#ifdef DBC
-	    struct Sentry
-	    {	Sentry() { ...preconditions... }
-		~Sentry() { ...postconditions... }
-	    } sentry;
-	#endif
-	    ...implementation...
-	}
-	
- - (One can make use of the C++ rule that templates are only - instantiated when used can be used to avoid the #ifdef, by - putting the conditions into a template function referenced - by the assert.) -

- - Let's add a return value to foo() that needs to be checked in - the postconditions. In D: - -

-	int foo()
-	    in { ...preconditions... }
-	    out (result) { ...postconditions... }
-	    body
-	    {
-		...implementation...
-		if (...)
-		    return bar();
-		return 3;
-	    }
-	
- - In C++: - -
-	int foo()
-	{
-	#ifdef DBC
-	    struct Sentry
-	    {	int result;
-		Sentry() { ...preconditions... }
-		~Sentry() { ...postconditions... }
-	    } sentry;
-	#endif
-	    ...implementation...
-	    if (...)
-	    {   int i = bar();
-	#ifdef DBC
-		sentry.result = i;
-	#endif
-		return i;
-	    }
-	#ifdef DBC
-	    sentry.result = 3;
-	#endif
-	    return 3;
-	}
-	
- - Now add a couple parameters to foo(). In D: - -
-	int foo(int a, int b)
-	    in { ...preconditions... }
-	    out (result) { ...postconditions... }
-	    body
-	    {
-		...implementation...
-		if (...)
-		    return bar();
-		return 3;
-	    }
-	
- - In C++: - -
-	int foo(int a, int b)
-	{
-	#ifdef DBC
-	    struct Sentry
-	    {	int a, b;
-		int result;
-		Sentry(int a, int b)
-		{   this->a = a;
-		    this->b = b;
-		    ...preconditions...
-		}
-		~Sentry() { ...postconditions... }
-	    } sentry(a,b);
-	#endif
-	    ...implementation...
-		if (...)
-		{   int i = bar();
-	#ifdef DBC
-		    sentry.result = i;
-	#endif
-		    return i;
-		}
-	#ifdef DBC
-		sentry.result = 3;
-	#endif
-		return 3;
-	}
-	
- -

Preconditions and Postconditions for Member Functions

- - Consider the use of preconditions and postconditions for a - polymorphic function in D: - -
-	class A
-	{
-	    void foo()
-		in { ...Apreconditions... }
-		out { ...Apostconditions... }
-		body
-		{
-		    ...implementation...
-		}
-	}
-
-	class B : A
-	{
-	    void foo()
-		in { ...Bpreconditions... }
-		out { ...Bpostconditions... }
-		body
-		{
-		    ...implementation...
-		}
-	}
-	
- - The semantics for a call to B.foo() are: - - - - Let's get this to work in C++: - -
-	class A
-	{
-	protected:
-	    #if DBC
-	    int foo_preconditions() { ...Apreconditions... }
-	    void foo_postconditions() { ...Apostconditions... }
-	    #else
-	    int foo_preconditions() { return 1; }
-	    void foo_postconditions() { }
-	    #endif
-
-	    void foo_internal()
-	    {
-		...implementation...
-	    }
-
-	public:
-	    virtual void foo()
-	    {
-		foo_preconditions();
-		foo_internal();
-		foo_postconditions();
-	    }
-	};
-
-	class B : A
-	{
-	protected:
-	    #if DBC
-	    int foo_preconditions() { ...Bpreconditions... }
-	    void foo_postconditions() { ...Bpostconditions... }
-	    #else
-	    int foo_preconditions() { return 1; }
-	    void foo_postconditions() { }
-	    #endif
-
-	    void foo_internal()
-	    {
-		...implementation...
-	    }
-
-	public:
-	    virtual void foo()
-	    {
-		assert(foo_preconditions() || A::foo_preconditions());
-		foo_internal();
-		A::foo_postconditions();
-		foo_postconditions();
-	    }
-	};
-	
- - Something interesting has happened here. The preconditions can - no longer be done using assert, since the results need - to be OR'd together. I'll leave as a reader exercise adding - in a class invariant, function return values for foo(), - and parameters - for foo(). - -

Conclusion

- - These C++ techniques can work up to a point. But, aside from - assert, they are not standardized and so will vary from - project to project. Furthermore, they require much tedious - adhesion to a particular convention, and add significant clutter - to the code. Perhaps that's why it's rarely seen in practice. -

- - By adding support for DbC into the language, D offers an easy - way to use DbC and get it right. Being in the language standardizes - the way it will be used from project to project. - -

References

- - Chapter C.11 introduces the theory and rationale of - Contract Programming in - - Object-Oriented Software Construction -
- Bertrand Meyer, Prentice Hall -

- - Chapters 24.3.7.1 to 24.3.7.3 discuss Contract Programming in C++ in - - The C++ Programming Language Special Edition -
- Bjarne Stroustrup, Addison-Wesley -

- -

Feedback and Comments

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

- - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - D's Contract Programming vs C++'s + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

D's Contract Programming vs C++'s

+ + Many people have written me saying that D's Contract Programming + (DbC) does not add anything that C++ does not already support. + They go on to illustrate their point with a technique for doing DbC in + C++. +

+ + It makes sense to review what DbC is, how it is done in D, + and stack that up with what each of the various C++ DbC techniques + can do. +

+ + Digital Mars C++ adds + extensions to C++ + to support DbC, but they are not covered here because they are not + part of standard C++ and are not supported by any other C++ compiler. + +

Contract Programming in D

+ + This is more fully documented in the D + Contract Programming document. + To sum up, DbC in D has the following characteristics: + +
    + +
  1. The assert is the basic contract. + +
  2. When an assert contract fails, it throws an exception. + Such exceptions can be caught and handled, or allowed to + terminate the program. + +
  3. Classes can have class invariants which are + checked upon entry and exit of each public class member function, + the exit of each constructor, and the entry of the destructor. + +
  4. Assert contracts on object references check the class + invariant for that object. + +
  5. Class invariants are inherited, that means that a derived + class invariant will implicitly call the base class invariant. + +
  6. Functions can have preconditions and postconditions. + +
  7. For member functions in a class inheritance hierarchy, the + precondition of a derived class function are OR'd together + with the preconditions of all the functions it overrides. + The postconditions are AND'd together. + +
  8. By throwing a compiler switch, DbC code can be enabled + or can be withdrawn from the compiled code. + +
  9. Code works semantically the same with or without DbC + checking enabled. + +
+ +

Contract Programming in C++

+ +

The assert Macro

+ + C++ does have the basic assert macro, which tests its argument + and if it fails, aborts the program. assert can be turned + on and off with the NDEBUG macro. +

+ + assert does not know anything about class invariants, + and does not throw an exception when it fails. It just aborts + the program after writing a message. assert relies on + a macro text preprocessor to work. +

+ + assert is where explicit support for DbC in Standard C++ + begins and ends. + +

Class Invariants

+ + Consider a class invariant in D: + +

+
+

+	class A
+	{
+	    invariant() { ...contracts... }
+
+	    this() { ... }	// constructor
+	    ~this() { ... }	// destructor
+
+	    void foo() { ... }	// public member function
+	}
+
+	class B : A
+	{
+	    invariant() { ...contracts... }
+	    ...
+	}
+	

+ + To accomplish the equivalent in C++ (thanks to Bob Bell for providing + this): + +

+
+

+	template
+	inline void check_invariant(T& iX)
+	{
+	#ifdef DBC
+	    iX.invariant();
+	#endif
+	}
+
+	// A.h:
+
+	class A {
+	    public:
+	#ifdef DBG
+	       virtual void invariant() { ...contracts... }
+	#endif
+	       void foo();
+	};
+
+	// A.cpp:
+
+	void A::foo()
+	{
+	    check_invariant(*this);
+	    ...
+	    check_invariant(*this);
+	}
+
+	// B.h:
+
+	#include "A.h"
+
+	class B : public A {
+	    public:
+	#ifdef DBG
+		virtual void invariant()
+		{ ...contracts...
+		   A::invariant();
+		}
+	#endif
+	       void bar();
+	};
+
+	// B.cpp:
+
+	void B::barG()
+	{
+	    check_invariant(*this);
+	    ...
+	    check_invariant(*this);
+	}
+	

+ + There's an additional complication with A::foo(). Upon every + normal exit from the function, the invariant() should be + called. + This means that code that looks like: + +

+
+

+	int A::foo()
+	{
+	    ...
+	    if (...)
+		return bar();
+	    return 3;
+	}
+	

+ + would need to be written as: + +

+
+

+	int A::foo()
+	{
+	    int result;
+	    check_invariant(*this);
+	    ...
+	    if (...)
+	    {
+		result = bar();
+		check_invariant(*this);
+		return result;
+	    }
+	    check_invariant(*this);
+	    return 3;
+	}
+	

+ + Or recode the function so it has a single exit point. + One possibility to mitigate this is to use RAII techniques: + +

+
+

+	int A::foo()
+	{
+	#if DBC
+	    struct Sentry {
+	       Sentry(A& iA) : mA(iA) { check_invariants(iA); }
+	       ~Sentry() { check_invariants(mA); }
+	       A& mA;
+	    } sentry(*this);
+	#endif
+	    ...
+	    if (...)
+		return bar();
+	    return 3;
+	}
+	

+ + The #if DBC is still there because some compilers may not + optimize the whole thing away if check_invariants compiles to nothing. + +

Preconditions and Postconditions

+ + Consider the following in D: + +

+
+

+	void foo()
+	    in { ...preconditions... }
+	    out { ...postconditions... }
+	    body
+	    {
+		...implementation...
+	    }
+	

+ + This is nicely handled in C++ with the nested Sentry struct: + +

+
+

+	void foo()
+	{
+	    struct Sentry
+	    {	Sentry() { ...preconditions... }
+		~Sentry() { ...postconditions... }
+	    } sentry;
+	    ...implementation...
+	}
+	

+ + If the preconditions and postconditions consist of nothing + more than assert macros, the whole doesn't need to + be wrapped in a #ifdef pair, since a good C++ compiler will + optimize the whole thing away if the asserts are turned off. +

+ + But suppose foo() sorts an array, and the postcondition needs + to walk the array and verify that it really is sorted. Now + the shebang needs to be wrapped in #ifdef: + +

+
+

+	void foo()
+	{
+	#ifdef DBC
+	    struct Sentry
+	    {	Sentry() { ...preconditions... }
+		~Sentry() { ...postconditions... }
+	    } sentry;
+	#endif
+	    ...implementation...
+	}
+	

+ + (One can make use of the C++ rule that templates are only + instantiated when used can be used to avoid the #ifdef, by + putting the conditions into a template function referenced + by the assert.) +

+ + Let's add a return value to foo() that needs to be checked in + the postconditions. In D: + +

+
+

+	int foo()
+	    in { ...preconditions... }
+	    out (result) { ...postconditions... }
+	    body
+	    {
+		...implementation...
+		if (...)
+		    return bar();
+		return 3;
+	    }
+	

+ + In C++: + +

+
+

+	int foo()
+	{
+	#ifdef DBC
+	    struct Sentry
+	    {	int result;
+		Sentry() { ...preconditions... }
+		~Sentry() { ...postconditions... }
+	    } sentry;
+	#endif
+	    ...implementation...
+	    if (...)
+	    {   int i = bar();
+	#ifdef DBC
+		sentry.result = i;
+	#endif
+		return i;
+	    }
+	#ifdef DBC
+	    sentry.result = 3;
+	#endif
+	    return 3;
+	}
+	

+ + Now add a couple parameters to foo(). In D: + +

+
+

+	int foo(int a, int b)
+	    in { ...preconditions... }
+	    out (result) { ...postconditions... }
+	    body
+	    {
+		...implementation...
+		if (...)
+		    return bar();
+		return 3;
+	    }
+	

+ + In C++: + +

+
+

+	int foo(int a, int b)
+	{
+	#ifdef DBC
+	    struct Sentry
+	    {	int a, b;
+		int result;
+		Sentry(int a, int b)
+		{   this->a = a;
+		    this->b = b;
+		    ...preconditions...
+		}
+		~Sentry() { ...postconditions... }
+	    } sentry(a,b);
+	#endif
+	    ...implementation...
+		if (...)
+		{   int i = bar();
+	#ifdef DBC
+		    sentry.result = i;
+	#endif
+		    return i;
+		}
+	#ifdef DBC
+		sentry.result = 3;
+	#endif
+		return 3;
+	}
+	

+ +

Preconditions and Postconditions for Member Functions

+ + Consider the use of preconditions and postconditions for a + polymorphic function in D: + +

+
+

+	class A
+	{
+	    void foo()
+		in { ...Apreconditions... }
+		out { ...Apostconditions... }
+		body
+		{
+		    ...implementation...
+		}
+	}
+
+	class B : A
+	{
+	    void foo()
+		in { ...Bpreconditions... }
+		out { ...Bpostconditions... }
+		body
+		{
+		    ...implementation...
+		}
+	}
+	

+ + The semantics for a call to B.foo() are: + +

+ + Let's get this to work in C++: + +

+
+

+	class A
+	{
+	protected:
+	    #if DBC
+	    int foo_preconditions() { ...Apreconditions... }
+	    void foo_postconditions() { ...Apostconditions... }
+	    #else
+	    int foo_preconditions() { return 1; }
+	    void foo_postconditions() { }
+	    #endif
+
+	    void foo_internal()
+	    {
+		...implementation...
+	    }
+
+	public:
+	    virtual void foo()
+	    {
+		foo_preconditions();
+		foo_internal();
+		foo_postconditions();
+	    }
+	};
+
+	class B : A
+	{
+	protected:
+	    #if DBC
+	    int foo_preconditions() { ...Bpreconditions... }
+	    void foo_postconditions() { ...Bpostconditions... }
+	    #else
+	    int foo_preconditions() { return 1; }
+	    void foo_postconditions() { }
+	    #endif
+
+	    void foo_internal()
+	    {
+		...implementation...
+	    }
+
+	public:
+	    virtual void foo()
+	    {
+		assert(foo_preconditions() || A::foo_preconditions());
+		foo_internal();
+		A::foo_postconditions();
+		foo_postconditions();
+	    }
+	};
+	

+ + Something interesting has happened here. The preconditions can + no longer be done using assert, since the results need + to be OR'd together. I'll leave as a reader exercise adding + in a class invariant, function return values for foo(), + and parameters + for foo(). + +

Conclusion

+ + These C++ techniques can work up to a point. But, aside from + assert, they are not standardized and so will vary from + project to project. Furthermore, they require much tedious + adhesion to a particular convention, and add significant clutter + to the code. Perhaps that's why it's rarely seen in practice. +

+ + By adding support for DbC into the language, D offers an easy + way to use DbC and get it right. Being in the language standardizes + the way it will be used from project to project. + +

References

+ + Chapter C.11 introduces the theory and rationale of + Contract Programming in + + Object-Oriented Software Construction +
+ Bertrand Meyer, Prentice Hall +

+ + Chapters 24.3.7.1 to 24.3.7.3 discuss Contract Programming in C++ in + + The C++ Programming Language Special Edition +
+ Bjarne Stroustrup, Addison-Wesley +

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/cppstrings.html dmd-0.124/dmd/html/d/cppstrings.html --- dmd-0.123/dmd/html/d/cppstrings.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/cppstrings.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,529 +1,598 @@ - - -D Programming Language - D Strings vs C++ Strings - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Oct 9, 2004 -


- -

D Strings vs C++ Strings

- - -Why have strings built-in to the core language of D rather than entirely in -a library as in C++ Strings? What's the point? Where's the improvement? - -

Concatenation Operator

- - C++ Strings are stuck with overloading existing operators. The - obvious choice for concatenation is += and +. - But someone just looking at the code will see + and think "addition". - He'll have to look up the types (and types are frequently buried - behind multiple typedef's) to see that it's a string type, and - it's not adding strings but concatenating them. -

- - Additionally, if one has an array of floats, is '+' overloaded to - be the same as a vector addition, or an array concatenation? -

- - In D, these problems are avoided by introducing a new binary - operator ~ as the concatenation operator. It works with - arrays (of which strings are a subset). ~= is the corresponding - append operator. ~ on arrays of floats would concatenate them, - + would imply a vector add. Adding a new operator makes it possible - for orthogonality and consistency in the treatment of arrays. - (In D, strings are simply arrays of characters, not a special - type.) - -

Interoperability With C String Syntax

- - Overloading of operators only really works if one of the operands - is overloadable. So the C++ string class cannot consistently - handle arbitrary expressions containing strings. Consider: - -
-	const char abc[5] = "world";
-	string str = "hello" + abc;
-
- - That isn't going to work. But it does work when the core language - knows about strings: - -
-	const char[5] abc = "world";
-	char[] str = "hello" ~ abc;
-
- -

Consistency With C String Syntax

- - There are three ways to find the length of a string in C++: - -
-	const char abc[] = "world";	:	sizeof(abc)/sizeof(abc[0])-1
-					:	strlen(abc)
-	string str			:	str.length()
-
- - That kind of inconsistency makes it hard to write generic templates. - Consider D: - -
-	char[5] abc = "world";	:	abc.length
-	char[] str		:	str.length
-
- -

Checking For Empty Strings

- - C++ strings use a function to determine if a string is empty: -
-	string str;
-	if (str.empty())
-		// string is empty
-
- - In D, an empty string is just null: - -
-	char[] str;
-	if (!str)
-		// string is empty
-
- - -

Resizing Existing String

- - C++ handles this with the resize() member function: - -
-	string str;
-	str.resize(newsize);
-
- - D takes advantage of knowing that str is a string, and - so resizing it is just changing the length property: - -
-	char[] str;
-	str.length = newsize;
-
- -

Slicing a String

- - C++ slices an existing string using a special constructor: - -
-	string s1 = "hello world";
-	string s2(s1, 6, 5);		// s2 is "world"
-
- - D has the array slice syntax, not possible with C++: - -
-	char[] s1 = "hello world";
-	char[] s2 = s1[6 .. 11];	// s2 is "world"
-
- - Slicing, of course, works with any array in D, not just strings. - -

Copying a String

- - C++ copies strings with the replace function: - -
-	string s1 = "hello world";
-	string s2 = "goodbye      ";
-	s2.replace(8, 5, s1, 6, 5);	// s2 is "goodbye world"
-
- - D uses the slice syntax as an lvalue: - -
-	char[] s1 = "hello world";
-	char[] s2 = "goodbye      ";
-	s2[8..13] = s1[6..11];		// s2 is "goodbye world"
-
- -

Conversions to C Strings

- - This is needed for compatibility with C API's. In C++, this - uses the c_str() member function: - -
-	void foo(const char *);
-	string s1;
-	foo(s1.c_str());
-
- - In D, strings can be implicitly converted to char*: - -
-	void foo(char *);
-	char[] s1;
-	foo(s1);
-
- - Note: some will argue that it is a mistake in D to have an implicit - conversion from char[] to char*. - -

Array Bounds Checking

- - In C++, string array bounds checking for [] is not done. - In D, array bounds checking is on by default and it can be turned off - with a compiler switch after the program is debugged. - -

String Switch Statements

- - Are not possible in C++, nor is there any way to add them - by adding more to the library. In D, they take the obvious - syntactical forms: - -
-	switch (str)
-	{
-	    case "hello":
-	    case "world":
-		...
-	}
-
- - where str can be any of literal "string"s, fixed string arrays - like char[10], or dynamic strings like char[]. A quality implementation - can, of course, explore many strategies of efficiently implementing - this based on the contents of the case strings. - -

Filling a String

- - In C++, this is done with the replace() member function: - -
-	string str = "hello";
-	str.replace(1,2,2,'?');		// str is "h??lo"
-
- - In D, use the array slicing syntax in the natural manner: - -
-	char[] str = "hello";
-	str[1..2] = '?';		// str is "h??lo"
-
- -

Value vs Reference

- - C++ strings, as implemented by STLport, are by value and are - 0-terminated. [The latter is an implementation choice, but - STLport seems to be the most popular implementation.] - This, coupled with no garbage collection, has - some consequences. First of all, any string created must make - its own copy of the string data. The 'owner' of the string - data must be kept track of, because when the owner is deleted - all references become invalid. If one tries to avoid the - dangling reference problem by treating strings as value types, - there will be a lot of overhead of memory allocation, - data copying, and memory deallocation. Next, the 0-termination - implies that strings cannot refer to other strings. String - data in the data segment, stack, etc., cannot - be referred to. -

- - D strings are reference types, and the memory is garbage collected. - This means that only references need to be copied, not the - string data. D strings can refer to data in the static data - segment, data on the stack, data inside other strings, objects, - file buffers, etc. There's no need to keep track of the 'owner' - of the string data. -

- - The obvious question is if multiple D strings refer to the same - string data, what happens if the data is modified? All the - references will now point to the modified data. This can have - its own consequences, which can be avoided if the copy-on-write - convention is followed. All copy-on-write is is that if - a string is written to, an actual copy of the string data is made - first. -

- - The result of D strings being reference only and garbage collected - is that code that does a lot of string manipulating, such as - an lzw compressor, can be a lot more efficient in terms of both - memory consumption and speed. - -

Benchmark

- - Let's take a look at a small utility, wordcount, that counts up - the frequency of each word in a text file. In D, it looks like this: - -
-	import file;
-
-	int main (char[][] args)
-	{
-	    int w_total;
-	    int l_total;
-	    int c_total;
-	    int[char[]] dictionary;
-
-	    printf("   lines   words   bytes file\n");
-	    for (int i = 1; i < args.length; ++i)
-	    {
-		char[] input;
-		int w_cnt, l_cnt, c_cnt;
-		int inword;
-		int wstart;
-
-		input = cast(char[])file.read(args[i]);
-
-		for (int j = 0; j < input.length; j++)
-		{   char c;
-
-		    c = input[j];
-		    if (c == '\n')
-			++l_cnt;
-		    if (c >= '0' && c <= '9')
-		    {
-		    }
-		    else if (c >= 'a' && c <= 'z' ||
-			c >= 'A' && c <= 'Z')
-		    {
-			if (!inword)
-			{
-			    wstart = j;
-			    inword = 1;
-			    ++w_cnt;
-			}
-		    }
-		    else if (inword)
-		    {   char[] word = input[wstart .. j];
-
-			dictionary[word]++;
-			inword = 0;
-		    }
-		    ++c_cnt;
-		}
-		if (inword)
-		{   char[] w = input[wstart .. input.length];
-		    dictionary[w]++;
-		}
-		printf("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, args[i]);
-		l_total += l_cnt;
-		w_total += w_cnt;
-		c_total += c_cnt;
-	    }
-
-	    if (args.length > 2)
-	    {
-		printf("--------------------------------------\n%8lu%8lu%8lu total",
-		    l_total, w_total, c_total);
-	    }
-
-	    printf("--------------------------------------\n");
-
-	    foreach (char[] word1; dictionary.keys.sort)
-	    {
-		printf("%3d %.*s\n", dictionary[word1], word1);
-	    }
-	    return 0;
-	}
-	
- - Two people have written C++ implementations using the C++ standard - template library, - wccpp1 - and - wccpp2. - The input file - alice30.txt - is the text of "Alice in Wonderland." - The D compiler, - dmd, - and the C++ compiler, - dmc, - share the same - optimizer and code generator, which provides a more apples to - apples comparison of the efficiency of the semantics of the languages - rather than the optimization and code generator sophistication. - Tests were run on a Win XP machine. dmc uses STLport for the template - implementation. -

- - - - - - -
Program - Compile - Compile Time - Run - Run Time -
D wc - dmd wc -O -release - 0.0719 - wc alice30.txt >log - 0.0326 -
C++ wccpp1 - dmc wccpp1 -o -I\dm\stlport\stlport - 2.1917 - wccpp1 alice30.txt >log - 0.0944 -
C++ wccpp2 - dmc wccpp2 -o -I\dm\stlport\stlport - 2.0463 - wccpp2 alice30.txt >log - 0.1012 -
-

- - The following tests were run on linux, again comparing a D compiler - (gdc) - and a C++ compiler (g++) that share a common optimizer and - code generator. The system is Pentium III 800MHz running RedHat Linux 8.0 - and gcc 3.4.2. - The Digital Mars D compiler for linux (dmd) - is included for comparison. -

- - - - - - - - -
Program - Compile - Compile Time - Run - Run Time -
D wc - gdc -O2 -frelease -o wc wc.d - 0.326 - wc alice30.txt > /dev/null - 0.041 -
D wc - dmd wc -O -release - 0.235 - wc alice30.txt > /dev/null - 0.041 -
C++ wccpp1 - g++ -O2 -o wccpp1 wccpp1.cc - 2.874 - wccpp1 alice30.txt > /dev/null - 0.086 -
C++ wccpp2 - g++ -O2 -o wccpp2 wccpp2.cc - 2.886 - wccpp2 alice30.txt > /dev/null - 0.095 -
-

- - These tests compare gdc with g++ on a PowerMac G5 2x2.0GHz - running MacOS X 10.3.5 and gcc 3.4.2. (Timings are a little - less accurate.) -

- - - - - - -
Program - Compile - Compile Time - Run - Run Time -
D wc - gdc -O2 -frelease -o wc wc.d - 0.28 - wc alice30.txt > /dev/null - 0.03 -
C++ wccpp1 - g++ -O2 -o wccpp1 wccpp1.cc - 1.90 - wccpp1 alice30.txt > /dev/null - 0.07 -
C++ wccpp2 - g++ -O2 -o wccpp2 wccpp2.cc - 1.88 - wccpp2 alice30.txt > /dev/null - 0.08 -
-


-

wccpp2 by Allan Odgaard

- -
-	#include <algorithm>
-	#include <cstdio>
-	#include <fstream>
-	#include <iterator>
-	#include <map>
-	#include <vector>
-
-	bool isWordStartChar (char c)	{ return isalpha(c); }
-	bool isWordEndChar (char c)	{ return !isalnum(c); }
-
-	int main (int argc, char const* argv[])
-	{
-	    using namespace std;
-	    printf("Lines Words Bytes File:\n");
-
-	    map<string, int> dict;
-	    int tLines = 0, tWords = 0, tBytes = 0;
-	    for(int i = 1; i < argc; i++)
-	    {
-		ifstream file(argv[i]);
-		istreambuf_iterator<char> from(file.rdbuf()), to;
-		vector<char> v(from, to);
-		vector<char>::iterator first = v.begin(), last = v.end(), bow, eow;
-
-		int numLines = count(first, last, '\n');
-		int numWords = 0;
-		int numBytes = last - first;
-
-		for(eow = first; eow != last; )
-		{
-		    bow = find_if(eow, last, isWordStartChar);
-		    eow = find_if(bow, last, isWordEndChar);
-		    if(bow != eow)
-			++dict[string(bow, eow)], ++numWords;
-		}
-
-		printf("%5d %5d %5d %s\n", numLines, numWords, numBytes, argv[i]);
-
-		tLines += numLines;
-		tWords += numWords;
-		tBytes += numBytes;
-	    }
-
-	    if(argc > 2)
-		    printf("-----------------------\n%5d %5d %5d\n", tLines, tWords, tBytes);
-	    printf("-----------------------\n\n");
-
-	    for(map<string, int>::const_iterator it = dict.begin(); it != dict.end(); ++it)
-		    printf("%5d %s\n", it->second, it->first.c_str());
-
-	    return 0;
-	}
-	
- - -

Feedback and Comments

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

- - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - D Strings vs C++ Strings + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

D Strings vs C++ Strings

+ + +Why have strings built-in to the core language of D rather than entirely in +a library as in C++ Strings? What's the point? Where's the improvement? + +

Concatenation Operator

+ + C++ Strings are stuck with overloading existing operators. The + obvious choice for concatenation is += and +. + But someone just looking at the code will see + and think "addition". + He'll have to look up the types (and types are frequently buried + behind multiple typedef's) to see that it's a string type, and + it's not adding strings but concatenating them. +

+ + Additionally, if one has an array of floats, is '+' overloaded to + be the same as a vector addition, or an array concatenation? +

+ + In D, these problems are avoided by introducing a new binary + operator ~ as the concatenation operator. It works with + arrays (of which strings are a subset). ~= is the corresponding + append operator. ~ on arrays of floats would concatenate them, + + would imply a vector add. Adding a new operator makes it possible + for orthogonality and consistency in the treatment of arrays. + (In D, strings are simply arrays of characters, not a special + type.) + +

Interoperability With C String Syntax

+ + Overloading of operators only really works if one of the operands + is overloadable. So the C++ string class cannot consistently + handle arbitrary expressions containing strings. Consider: + +

+
+

+        const char abc[5] = "world";
+        string str = "hello" + abc;
+
+

+ + That isn't going to work. But it does work when the core language + knows about strings: + +

+
+

+	const char[5] abc = "world";
+	char[] str = "hello" ~ abc;
+
+

+ +

Consistency With C String Syntax

+ + There are three ways to find the length of a string in C++: + +

+
+

+	const char abc[] = "world";	:	sizeof(abc)/sizeof(abc[0])-1
+					:	strlen(abc)
+	string str			:	str.length()
+
+

+ + That kind of inconsistency makes it hard to write generic templates. + Consider D: + +

+
+

+	char[5] abc = "world";	:	abc.length
+	char[] str		:	str.length
+
+

+ +

Checking For Empty Strings

+ + C++ strings use a function to determine if a string is empty: +

+
+

+	string str;
+	if (str.empty())
+		// string is empty
+

+ + In D, an empty string is just null: + +

+
+

+	char[] str;
+	if (!str)
+		// string is empty
+

+ + +

Resizing Existing String

+ + C++ handles this with the resize() member function: + +

+
+

+	string str;
+	str.resize(newsize);
+

+ + D takes advantage of knowing that str is a string, and + so resizing it is just changing the length property: + +

+
+

+	char[] str;
+	str.length = newsize;
+

+ +

Slicing a String

+ + C++ slices an existing string using a special constructor: + +

+
+

+	string s1 = "hello world";
+	string s2(s1, 6, 5);		// s2 is "world"
+

+ + D has the array slice syntax, not possible with C++: + +

+
+

+	char[] s1 = "hello world";
+	char[] s2 = s1[6 .. 11];	// s2 is "world"
+

+ + Slicing, of course, works with any array in D, not just strings. + +

Copying a String

+ + C++ copies strings with the replace function: + +

+
+

+	string s1 = "hello world";
+	string s2 = "goodbye      ";
+	s2.replace(8, 5, s1, 6, 5);	// s2 is "goodbye world"
+

+ + D uses the slice syntax as an lvalue: + +

+
+

+	char[] s1 = "hello world";
+	char[] s2 = "goodbye      ";
+	s2[8..13] = s1[6..11];		// s2 is "goodbye world"
+

+ +

Conversions to C Strings

+ + This is needed for compatibility with C API's. In C++, this + uses the c_str() member function: + +

+
+

+	void foo(const char *);
+	string s1;
+	foo(s1.c_str());
+

+ + In D, strings can be implicitly converted to char*: + +

+
+

+	void foo(char *);
+	char[] s1;
+	foo(s1);
+

+ + Note: some will argue that it is a mistake in D to have an implicit + conversion from char[] to char*. + +

Array Bounds Checking

+ + In C++, string array bounds checking for [] is not done. + In D, array bounds checking is on by default and it can be turned off + with a compiler switch after the program is debugged. + +

String Switch Statements

+ + Are not possible in C++, nor is there any way to add them + by adding more to the library. In D, they take the obvious + syntactical forms: + +

+
+

+	switch (str)
+	{
+	    case "hello":
+	    case "world":
+		...
+	}
+

+ + where str can be any of literal "string"s, fixed string arrays + like char[10], or dynamic strings like char[]. A quality implementation + can, of course, explore many strategies of efficiently implementing + this based on the contents of the case strings. + +

Filling a String

+ + In C++, this is done with the replace() member function: + +

+
+

+	string str = "hello";
+	str.replace(1,2,2,'?');		// str is "h??lo"
+

+ + In D, use the array slicing syntax in the natural manner: + +

+
+

+	char[] str = "hello";
+	str[1..2] = '?';		// str is "h??lo"
+

+ +

Value vs Reference

+ + C++ strings, as implemented by STLport, are by value and are + 0-terminated. [The latter is an implementation choice, but + STLport seems to be the most popular implementation.] + This, coupled with no garbage collection, has + some consequences. First of all, any string created must make + its own copy of the string data. The 'owner' of the string + data must be kept track of, because when the owner is deleted + all references become invalid. If one tries to avoid the + dangling reference problem by treating strings as value types, + there will be a lot of overhead of memory allocation, + data copying, and memory deallocation. Next, the 0-termination + implies that strings cannot refer to other strings. String + data in the data segment, stack, etc., cannot + be referred to. +

+ + D strings are reference types, and the memory is garbage collected. + This means that only references need to be copied, not the + string data. D strings can refer to data in the static data + segment, data on the stack, data inside other strings, objects, + file buffers, etc. There's no need to keep track of the 'owner' + of the string data. +

+ + The obvious question is if multiple D strings refer to the same + string data, what happens if the data is modified? All the + references will now point to the modified data. This can have + its own consequences, which can be avoided if the copy-on-write + convention is followed. All copy-on-write is is that if + a string is written to, an actual copy of the string data is made + first. +

+ + The result of D strings being reference only and garbage collected + is that code that does a lot of string manipulating, such as + an lzw compressor, can be a lot more efficient in terms of both + memory consumption and speed. + +

Benchmark

+ + Let's take a look at a small utility, wordcount, that counts up + the frequency of each word in a text file. In D, it looks like this: + +

+
+

+	import file;
+
+	int main (char[][] args)
+	{
+	    int w_total;
+	    int l_total;
+	    int c_total;
+	    int[char[]] dictionary;
+
+	    printf("   lines   words   bytes file\n");
+	    for (int i = 1; i < args.length; ++i)
+	    {
+		char[] input;
+		int w_cnt, l_cnt, c_cnt;
+		int inword;
+		int wstart;
+
+		input = cast(char[])file.read(args[i]);
+
+		for (int j = 0; j < input.length; j++)
+		{   char c;
+
+		    c = input[j];
+		    if (c == '\n')
+			++l_cnt;
+		    if (c >= '0' && c <= '9')
+		    {
+		    }
+		    else if (c >= 'a' && c <= 'z' ||
+			c >= 'A' && c <= 'Z')
+		    {
+			if (!inword)
+			{
+			    wstart = j;
+			    inword = 1;
+			    ++w_cnt;
+			}
+		    }
+		    else if (inword)
+		    {   char[] word = input[wstart .. j];
+
+			dictionary[word]++;
+			inword = 0;
+		    }
+		    ++c_cnt;
+		}
+		if (inword)
+		{   char[] w = input[wstart .. input.length];
+		    dictionary[w]++;
+		}
+		printf("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, args[i]);
+		l_total += l_cnt;
+		w_total += w_cnt;
+		c_total += c_cnt;
+	    }
+
+	    if (args.length > 2)
+	    {
+		printf("--------------------------------------\n%8lu%8lu%8lu total",
+		    l_total, w_total, c_total);
+	    }
+
+	    printf("--------------------------------------\n");
+
+	    foreach (char[] word1; dictionary.keys.sort)
+	    {
+		printf("%3d %.*s\n", dictionary[word1], word1);
+	    }
+	    return 0;
+	}
+	

+ + Two people have written C++ implementations using the C++ standard + template library, + wccpp1 + and + wccpp2. + The input file + alice30.txt + is the text of "Alice in Wonderland." + The D compiler, + dmd, + and the C++ compiler, + dmc, + share the same + optimizer and code generator, which provides a more apples to + apples comparison of the efficiency of the semantics of the languages + rather than the optimization and code generator sophistication. + Tests were run on a Win XP machine. dmc uses STLport for the template + implementation. +

+ + + + + + +
Program + Compile + Compile Time + Run + Run Time +
D wc + dmd wc -O -release + 0.0719 + wc alice30.txt >log + 0.0326 +
C++ wccpp1 + dmc wccpp1 -o -I\dm\stlport\stlport + 2.1917 + wccpp1 alice30.txt >log + 0.0944 +
C++ wccpp2 + dmc wccpp2 -o -I\dm\stlport\stlport + 2.0463 + wccpp2 alice30.txt >log + 0.1012 +
+

+ + The following tests were run on linux, again comparing a D compiler + (gdc) + and a C++ compiler (g++) that share a common optimizer and + code generator. The system is Pentium III 800MHz running RedHat Linux 8.0 + and gcc 3.4.2. + The Digital Mars D compiler for linux (dmd) + is included for comparison. +

+ + + + + + + + +
Program + Compile + Compile Time + Run + Run Time +
D wc + gdc -O2 -frelease -o wc wc.d + 0.326 + wc alice30.txt > /dev/null + 0.041 +
D wc + dmd wc -O -release + 0.235 + wc alice30.txt > /dev/null + 0.041 +
C++ wccpp1 + g++ -O2 -o wccpp1 wccpp1.cc + 2.874 + wccpp1 alice30.txt > /dev/null + 0.086 +
C++ wccpp2 + g++ -O2 -o wccpp2 wccpp2.cc + 2.886 + wccpp2 alice30.txt > /dev/null + 0.095 +
+

+ + These tests compare gdc with g++ on a PowerMac G5 2x2.0GHz + running MacOS X 10.3.5 and gcc 3.4.2. (Timings are a little + less accurate.) +

+ + + + + + +
Program + Compile + Compile Time + Run + Run Time +
D wc + gdc -O2 -frelease -o wc wc.d + 0.28 + wc alice30.txt > /dev/null + 0.03 +
C++ wccpp1 + g++ -O2 -o wccpp1 wccpp1.cc + 1.90 + wccpp1 alice30.txt > /dev/null + 0.07 +
C++ wccpp2 + g++ -O2 -o wccpp2 wccpp2.cc + 1.88 + wccpp2 alice30.txt > /dev/null + 0.08 +
+


+

wccpp2 by Allan Odgaard

+ +

+
+

+	#include <algorithm>
+	#include <cstdio>
+	#include <fstream>
+	#include <iterator>
+	#include <map>
+	#include <vector>
+
+	bool isWordStartChar (char c)	{ return isalpha(c); }
+	bool isWordEndChar (char c)	{ return !isalnum(c); }
+
+	int main (int argc, char const* argv[])
+	{
+	    using namespace std;
+	    printf("Lines Words Bytes File:\n");
+
+	    map<string, int> dict;
+	    int tLines = 0, tWords = 0, tBytes = 0;
+	    for(int i = 1; i < argc; i++)
+	    {
+		ifstream file(argv[i]);
+		istreambuf_iterator<char> from(file.rdbuf()), to;
+		vector<char> v(from, to);
+		vector<char>::iterator first = v.begin(), last = v.end(), bow, eow;
+
+		int numLines = count(first, last, '\n');
+		int numWords = 0;
+		int numBytes = last - first;
+
+		for(eow = first; eow != last; )
+		{
+		    bow = find_if(eow, last, isWordStartChar);
+		    eow = find_if(bow, last, isWordEndChar);
+		    if(bow != eow)
+			++dict[string(bow, eow)], ++numWords;
+		}
+
+		printf("%5d %5d %5d %s\n", numLines, numWords, numBytes, argv[i]);
+
+		tLines += numLines;
+		tWords += numWords;
+		tBytes += numBytes;
+	    }
+
+	    if(argc > 2)
+		    printf("-----------------------\n%5d %5d %5d\n", tLines, tWords, tBytes);
+	    printf("-----------------------\n\n");
+
+	    for(map<string, int>::const_iterator it = dict.begin(); it != dict.end(); ++it)
+		    printf("%5d %s\n", it->second, it->first.c_str());
+
+	    return 0;
+	}
+	

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/cpptod.html dmd-0.124/dmd/html/d/cpptod.html --- dmd-0.123/dmd/html/d/cpptod.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/cpptod.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,605 +1,809 @@ - - - - - -Digital Mars - Programming in D for C++ Programmers - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Feb 10, 2005 -


- -

Programming in D for C++ Programmers

- - -Every experienced C++ programmer accumulates a series of idioms and techniques -which become second nature. Sometimes, when learning a new language, those -idioms can be so comfortable it's hard to see how to do the equivalent in the -new language. So here's a collection of common C++ techniques, and how to do the -corresponding task in D. -

- -See also: Programming in D for C Programmers - -

- -C++ - -
- -

Defining constructors

- -

The C++ Way

- - Constructors have the same name as the class: - -
-	class Foo
-	{
-		Foo(int x);
-	};
-	
- -

The D Way

- - Constructors are defined with the this keyword: - -
-	class Foo
-	{
-		this(int x) { }
-	}
-	
- - which reflects how they are used in D. - -
-

Base class initialization

- -

The C++ Way

- - Base constructors are called using the base initializer syntax. - -
-	class A { A() {... } };
-	class B : A
-	{
-	     B(int x)
-		: A()		// call base constructor
-	     {	...
-	     }
-	};
-	
- -

The D Way

- - The base class constructor is called with the super syntax: - -
-	class A { this() { ... } }
-	class B : A
-	{
-	     this(int x)
-	     {	...
-		super();		// call base constructor
-		...
-	     }
-	}
-	
- - It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived - constructor. D can also have one constructor call another one: - -
-	class A
-	{	int a;
-		int b;
-		this() { a = 7; b = foo(); }
-		this(int x)
-		{
-		    this();
-		    a = x;
-		}
-	}
-	
- - Members can also be initialized to constants before the constructor is ever called, so the above example is - equivalently written as: - -
-	class A
-	{	int a = 7;
-		int b;
-		this() { b = foo(); }
-		this(int x)
-		{
-		    this();
-		    a = x;
-		}
-	}
-	
- -
-

Comparing structs

- -

The C++ Way

- - While C++ defines struct assignment in a simple, convenient manner: - -
-	struct A x, y;
-	...
-	x = y;
-	
- - it does not for struct comparisons. Hence, to compare two struct - instances for equality: - -
-	#include <string.h>
-
-	struct A x, y;
-
-	inline bool operator==(const A& x, const A& y)
-	{
-	    return (memcmp(&x, &y, sizeof(struct A)) == 0);
-	}
-	...
-	if (x == y)
-	    ...
-	
- - Note that the operator overload must be done for every struct - needing to be compared, and the implementation of that overloaded - operator is free of any language help with type checking. - The C++ way has an additional problem in that just inspecting the - (x == y) does not give a clue what is actually happening, you have - to go and find the particular overloaded operator==() that applies - to verify what it really does. -

- - There's a nasty bug lurking in the memcmp() implementation of operator==(). - The layout of a struct, due to alignment, can have 'holes' in it. - C++ does not guarantee those holes are assigned any values, and so - two different struct instances can have the same value for each member, - but compare different because the holes contain different garbage. -

- - To address this, the operator==() can be implemented to do a memberwise - compare. Unfortunately, this is unreliable because (1) if a member is added - to the struct definition one may forget to add it to operator==(), and - (2) floating point nan values compare unequal even if their bit patterns - match. -

- - There just is no robust solution in C++. - -

The D Way

- - D does it the obvious, straightforward way: - -
-	A x, y;
-	...
-	if (x == y)
-	    ...
-	
- -
-

Creating a new typedef'd type

- -

The C++ Way

- - Typedef's in C++ are weak, that is, they really do not introduce - a new type. The compiler doesn't distinguish between a typedef - and its underlying type. - -
-	#define HANDLE_INIT	((Handle)(-1))
-	typedef void *Handle;
-	void foo(void *);
-	void bar(Handle);
-
-	Handle h = HANDLE_INIT;
-	foo(h);			// coding bug not caught
-	bar(h);			// ok
-	
- - The C++ solution is to create a dummy struct whose sole - purpose is to get type checking and overloading on the new type. - -
-	#define HANDLE_INIT	((void *)(-1))
-	struct Handle
-	{   void *ptr;
-	    Handle() { ptr = HANDLE_INIT; }	// default initializer
-	    Handle(int i) { ptr = (void *)i; }
-	    operator void*() { return ptr; }	// conversion to underlying type
-	};
-	void bar(Handle);
-
-	Handle h;
-	bar(h);
-	h = func();
-	if (h != HANDLE_INIT)
-	    ...
-	
- -

The D Way

- - No need for idiomatic constructions like the above. Just write: - -
-	typedef void *Handle = cast(void *)-1;
-	void bar(Handle);
-
-	Handle h;
-	bar(h);
-	h = func();
-	if (h != Handle.init)
-	    ...
-	
- - Note how a default initializer can be supplied for the typedef as - a value of the underlying type. - -
-

Friends

- -

The C++ Way

- - Sometimes two classes are tightly related but not by inheritance, - but need to access each other's private members. This is done - using friend declarations: - -
-	class A
-	{
-	    private:
-		int a;
-
-	    public:
-		int foo(B *j);
-		friend class B;
-		friend int abc(A *);
-	};
-
-	class B
-	{
-	    private:
-		int b;
-
-	    public:
-		int bar(A *j);
-		friend class A;
-	};
-
-	int A::foo(B *j) { return j->b; }
-	int B::bar(A *j) { return j->a; }
-
-	int abc(A *p) { return p->a; }
-	
- -

The D Way

- - In D, friend access is implicit in being a member of the same - module. It makes sense that tightly related classes should be - in the same module, so implicitly granting friend access to - other module members solves the problem neatly: - -
-	module X;
-
-	class A
-	{
-	    private:
-		static int a;
-
-	    public:
-		int foo(B j) { return j.b; }
-	}
-
-	class B
-	{
-	    private:
-		static int b;
-
-	    public:
-		int bar(A j) { return j.a; }
-	}
-
-	int abc(A p) { return p.a; }
-	
- - The private attribute prevents other modules from - accessing the members. - -
-

Operator overloading

- -

The C++ Way

- - Given a struct that creates a new arithmetic data type, - it's convenient to overload the comparison operators so - it can be compared against integers: - -
-	struct A
-	{
-		int operator <  (int i);
-		int operator <= (int i);
-		int operator >  (int i);
-		int operator >= (int i);
-	};
-
-	int operator <  (int i, A &a) { return a >  i; }
-	int operator <= (int i, A &a) { return a >= i; }
-	int operator >  (int i, A &a) { return a <  i; }
-	int operator >= (int i, A &a) { return a <= i; }
-
- - A total of 8 functions are necessary. - -

The D Way

- - D recognizes that the comparison operators are all fundamentally - related to each other. So only one function is necessary: - -
-	struct A
-	{
-		int opCmp(int i);
-	}
-	
- - The compiler automatically interprets all the - <, <=, > and >= - operators in terms of the cmp function, as well - as handling the cases where the left operand is not an - object reference. -

- - Similar sensible rules hold for other operator overloads, - making using operator overloading in D much less tedious and less - error prone. Far less code needs to be written to accomplish - the same effect. - -


-

Namespace using declarations

- -

The C++ Way

- - A using-declaration in C++ is used to bring a name from - a namespace scope into the current scope: -
-	namespace Foo
-	{
-	    int x;
-	}
-	using Foo::x;
-	
- -

The D Way

- - D uses modules instead of namespaces and #include files, and - alias declarations take the place of using declarations: -
-	---- Module Foo.d ------
-	module Foo;
-	int x;
-
-	---- Another module ----
-	import Foo;
-	alias Foo.x x;
-	
- - Alias is a much more flexible than the single purpose using - declaration. Alias can be used to rename symbols, refer to - template members, refer to nested class types, etc. - -
-

RAII (Resource Acquisition Is Initialization)

- -

The C++ Way

- - In C++, resources like memory, etc., all need to be handled - explicitly. Since destructors automatically get called when - leaving a scope, RAII is implemented by putting the resource - release code into the destructor: -
-	class File
-	{   Handle *h;
-
-	    ~File()
-	    {
-		h->release();
-	    }
-	};
-	
- -

The D Way

- - The bulk of resource release problems are simply keeping track - of and freeing memory. This is handled automatically in D by - the garbage collector. The second common resources used are semaphores - and locks, handled automatically with D's synchronized - declarations and statements. -

- - The few RAII issues left are handled by auto classes. - Auto classes get their destructors run when they go out of scope. - -

-	auto class File
-	{   Handle h;
-
-	    ~this()
-	    {
-		h.release();
-	    }
-	}
-
-	void test()
-	{
-	    if (...)
-	    {   auto File f = new File();
-		...
-	    } // f.~this() gets run at closing brace, even if
-	      // scope was exited via a thrown exception
-	}
-	
- -
-

Properties

- -

The C++ Way

- - It is common practice to define a field, - along with object-oriented - get and set functions for it: - -
-	class Abc
-	{
-	  public:
-	    void setProperty(int newproperty) { property = newproperty; }
-	    int getProperty() { return property; }
-
-	  private:
-	    int property;
-	};
-
-	Abc a;
-	a.setProperty(3);
-	int x = a.getProperty();
-	
- - All this is quite a bit of typing, and it tends to make - code unreadable by filling - it with getProperty() and setProperty() calls. - -

The D Way

- - Properties can be get and set using the normal field syntax, - yet the get and set will invoke methods instead. - -
-	class Abc
-	{
-	    void property(int newproperty) { myprop = newproperty; } // set
-	    int property() { return myprop; }	// get
-
-	  private:
-	    int myprop;
-	}
-	
- - which is used as: - -
-	Abc a;
-	a.property = 3;		// equivalent to a.property(3)
-	int x = a.property;	// equivalent to int x = a.property()
-	
- - Thus, in D a property can be treated like it was a simple field name. - A property can start out actually being a simple field name, - but if later if becomes - necessary to make getting and setting it function calls, - no code needs to be modified other - than the class definition. - It obviates the wordy practice of defining get and set properties - 'just in case' a derived class should need to override them. - It's also a way to have interface classes, which do not have - data fields, behave syntactically as if they did. - -
-

Recursive Templates

- -

The C++ Way

- - An advanced use of templates is to recursively expand - them, relying on specialization to end it. A template - to compute a factorial would be: - -
-	template<int n> class factorial
-	{
-	    public:
-		enum { result = n * factorial<n - 1>::result };
-	};
-
-	template<> class factorial<1>
-	{
-	    public:
-		enum { result = 1 };
-	};
-
-	void test()
-	{
-	    printf("%d\n", factorial<4>::result); // prints 24
-	}
-	
- -

The D Way

- - The D version is analogous, though a little simpler, taking - advantage of promotion of single template members to the - enclosing name space: - -
-	template factorial(int n)
-	{
-	    enum { factorial = n* .factorial!(n-1) }
-	}
-
-	template factorial(int n : 1)
-	{
-	    enum { factorial = 1 }
-	}
-
-	void test()
-	{
-	    printf("%d\n", factorial!(4));	// prints 24
-	}
-	
- - -

Feedback and Comments

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

- - - + + + + + + + + + + + + + + + + + + + + + + +Digital Mars - Programming in D for C++ Programmers + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

Programming in D for C++ Programmers

+ +C++ + +Every experienced C++ programmer accumulates a series of idioms and techniques +which become second nature. Sometimes, when learning a new language, those +idioms can be so comfortable it's hard to see how to do the equivalent in the +new language. So here's a collection of common C++ techniques, and how to do the +corresponding task in D. +

+ +See also: Programming in D for C Programmers + +

+ + +
+ +

Defining constructors

+ +

The C++ Way

+ + Constructors have the same name as the class: + +

+
+

+	class Foo
+	{
+		Foo(int x); 
+	};

+ +

The D Way

+ + Constructors are defined with the this keyword: + +

+
+

+	class Foo
+	{
+		this(int x) { } 
+	}

+ + which reflects how they are used in D. + +


+

Base class initialization

+ +

The C++ Way

+ + Base constructors are called using the base initializer syntax. + +

+
+

+	class A { A() {... } };
+	class B : A
+	{
+	     B(int x)
+		: A()		// call base constructor 
+	     {	...
+	     }
+	};

+ +

The D Way

+ + The base class constructor is called with the super syntax: + +

+
+

+	class A { this() { ... } }
+	class B : A
+	{
+	     this(int x)
+	     {	...
+		super();	// call base constructor 
+		...
+	     }
+	}

+ + It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived + constructor. D can also have one constructor call another one: + +

+
+

+	class A
+	{	int a;
+		int b;
+		this() { a = 7; b = foo(); } 
+		this(int x)
+		{
+		    this();
+		    a = x;
+		}
+	}

+ + Members can also be initialized to constants before the constructor is ever called, so the above example is + equivalently written as: + +

+
+

+	class A
+	{	int a = 7;
+		int b;
+		this() { b = foo(); } 
+		this(int x)
+		{
+		    this();
+		    a = x;
+		}
+	}

+ +


+

Comparing structs

+ +

The C++ Way

+ + While C++ defines struct assignment in a simple, convenient manner: + +

+
+

+	struct A x, y; 
+	...
+	x = y;
+	

+ + it does not for struct comparisons. Hence, to compare two struct + instances for equality: + +

+
+

+	#include <string.h>
+
+	struct A x, y;
+
+	inline bool operator==(const A& x, const A& y)
+	{
+	    return (memcmp(&x, &y, sizeof(struct A)) == 0); 
+	}
+	...
+	if (x == y)
+	    ...
+	

+ + Note that the operator overload must be done for every struct + needing to be compared, and the implementation of that overloaded + operator is free of any language help with type checking. + The C++ way has an additional problem in that just inspecting the + (x == y) does not give a clue what is actually happening, you have + to go and find the particular overloaded operator==() that applies + to verify what it really does. +

+ + There's a nasty bug lurking in the memcmp() implementation of operator==(). + The layout of a struct, due to alignment, can have 'holes' in it. + C++ does not guarantee those holes are assigned any values, and so + two different struct instances can have the same value for each member, + but compare different because the holes contain different garbage. +

+ + To address this, the operator==() can be implemented to do a memberwise + compare. Unfortunately, this is unreliable because (1) if a member is added + to the struct definition one may forget to add it to operator==(), and + (2) floating point nan values compare unequal even if their bit patterns + match. +

+ + There just is no robust solution in C++. + +

The D Way

+ + D does it the obvious, straightforward way: + +

+
+

+	A x, y;
+	...
+	if (x == y) 
+	    ...
+	

+ +


+

Creating a new typedef'd type

+ +

The C++ Way

+ + Typedef's in C++ are weak, that is, they really do not introduce + a new type. The compiler doesn't distinguish between a typedef + and its underlying type. + +

+
+

+	#define HANDLE_INIT	((Handle)(-1))
+	typedef void *Handle;
+	void foo(void *);
+	void bar(Handle);
+
+	Handle h = HANDLE_INIT;
+	foo(h);			// coding bug not caught 
+	bar(h);			// ok
+	

+ + The C++ solution is to create a dummy struct whose sole + purpose is to get type checking and overloading on the new type. + +

+
+

+	#define HANDLE_INIT	((void *)(-1)) 
+	struct Handle
+	{   void *ptr;
+
+	    // default initializer
+	    Handle() { ptr = HANDLE_INIT; }
+
+	    Handle(int i) { ptr = (void *)i; }
+
+	    // conversion to underlying type 
+	    operator void*() { return ptr; }
+	};
+	void bar(Handle);
+
+	Handle h;
+	bar(h);
+	h = func();
+	if (h != HANDLE_INIT)
+	    ...
+	

+ +

The D Way

+ + No need for idiomatic constructions like the above. Just write: + +

+
+

+	typedef void *Handle = cast(void *)-1; 
+	void bar(Handle);
+
+	Handle h;
+	bar(h);
+	h = func();
+	if (h != Handle.init)
+	    ...
+	

+ + Note how a default initializer can be supplied for the typedef as + a value of the underlying type. + +


+

Friends

+ +

The C++ Way

+ + Sometimes two classes are tightly related but not by inheritance, + but need to access each other's private members. This is done + using friend declarations: + +

+
+

+	class A
+	{
+	    private:
+		int a;
+
+	    public:
+		int foo(B *j);
+		friend class B;
+		friend int abc(A *);
+	};
+
+	class B
+	{
+	    private:
+		int b;
+
+	    public:
+		int bar(A *j);
+		friend class A;
+	};
+
+	int A::foo(B *j) { return j->b; }
+	int B::bar(A *j) { return j->a; } 
+
+	int abc(A *p) { return p->a; }
+	

+ +

The D Way

+ + In D, friend access is implicit in being a member of the same + module. It makes sense that tightly related classes should be + in the same module, so implicitly granting friend access to + other module members solves the problem neatly: + +

+
+

+	module X;
+
+	class A
+	{
+	    private:
+		static int a;
+
+	    public:
+		int foo(B j) { return j.b; }
+	}
+
+	class B
+	{
+	    private:
+		static int b;
+
+	    public:
+		int bar(A j) { return j.a; } 
+	}
+
+	int abc(A p) { return p.a; }
+	

+ + The private attribute prevents other modules from + accessing the members. + +


+

Operator overloading

+ +

The C++ Way

+ + Given a struct that creates a new arithmetic data type, + it's convenient to overload the comparison operators so + it can be compared against integers: + +

+
+

+	struct A
+	{
+		int operator <  (int i);
+		int operator <= (int i);
+		int operator >  (int i);
+		int operator >= (int i);
+	};
+
+	int operator <  (int i, A &a) { return a >  i; }
+	int operator <= (int i, A &a) { return a >= i; }
+	int operator >  (int i, A &a) { return a <  i; }
+	int operator >= (int i, A &a) { return a <= i; } 
+	

+ + A total of 8 functions are necessary. + +

The D Way

+ + D recognizes that the comparison operators are all fundamentally + related to each other. So only one function is necessary: + +

+
+

+	struct A
+	{
+		int opCmp(int i); 
+	}
+	

+ + The compiler automatically interprets all the + <, <=, > and >= + operators in terms of the cmp function, as well + as handling the cases where the left operand is not an + object reference. +

+ + Similar sensible rules hold for other operator overloads, + making using operator overloading in D much less tedious and less + error prone. Far less code needs to be written to accomplish + the same effect. + +


+

Namespace using declarations

+ +

The C++ Way

+ + A using-declaration in C++ is used to bring a name from + a namespace scope into the current scope: + +

+
+

+	namespace Foo 
+	{
+	    int x;
+	}
+	using Foo::x;
+	

+ +

The D Way

+ + D uses modules instead of namespaces and #include files, and + alias declarations take the place of using declarations: + +

+
+

+	---- Module Foo.d ------
+	module Foo;
+	int x;
+
+	---- Another module ---- 
+	import Foo;
+	alias Foo.x x;
+	

+ + Alias is a much more flexible than the single purpose using + declaration. Alias can be used to rename symbols, refer to + template members, refer to nested class types, etc. + +


+

RAII (Resource Acquisition Is Initialization)

+ +

The C++ Way

+ + In C++, resources like memory, etc., all need to be handled + explicitly. Since destructors automatically get called when + leaving a scope, RAII is implemented by putting the resource + release code into the destructor: + +

+
+

+	class File
+	{   Handle *h;
+
+	    ~File()
+	    {
+		h->release(); 
+	    }
+	};
+	

+ +

The D Way

+ + The bulk of resource release problems are simply keeping track + of and freeing memory. This is handled automatically in D by + the garbage collector. The second common resources used are semaphores + and locks, handled automatically with D's synchronized + declarations and statements. +

+ + The few RAII issues left are handled by auto classes. + Auto classes get their destructors run when they go out of scope. + +

+
+

+	auto class File
+	{   Handle h;
+
+	    ~this()
+	    {
+		h.release();
+	    }
+	}
+
+	void test()
+	{
+	    if (...)
+	    {   auto File f = new File();
+		...
+	    } // f.~this() gets run at closing brace, even if 
+	      // scope was exited via a thrown exception
+	}
+	

+ +


+

Properties

+ +

The C++ Way

+ + It is common practice to define a field, + along with object-oriented + get and set functions for it: + +

+
+

+	class Abc
+	{
+	  public:
+	    void setProperty(int newproperty) { property = newproperty; } 
+	    int getProperty() { return property; }
+
+	  private:
+	    int property;
+	};
+
+	Abc a;
+	a.setProperty(3);
+	int x = a.getProperty();
+	

+ + All this is quite a bit of typing, and it tends to make + code unreadable by filling + it with getProperty() and setProperty() calls. + +

The D Way

+ + Properties can be get and set using the normal field syntax, + yet the get and set will invoke methods instead. + +

+
+

+	class Abc
+	{
+	    // set 
+	    void property(int newproperty) { myprop = newproperty; }
+
+	    // get
+	    int property() { return myprop; }
+
+	  private:
+	    int myprop;
+	}
+	

+ + which is used as: + +

+
+

+	Abc a;
+	a.property = 3;		// equivalent to a.property(3)
+	int x = a.property;	// equivalent to int x = a.property() 
+	

+ + Thus, in D a property can be treated like it was a simple field name. + A property can start out actually being a simple field name, + but if later if becomes + necessary to make getting and setting it function calls, + no code needs to be modified other + than the class definition. + It obviates the wordy practice of defining get and set properties + 'just in case' a derived class should need to override them. + It's also a way to have interface classes, which do not have + data fields, behave syntactically as if they did. + +


+

Recursive Templates

+ +

The C++ Way

+ + An advanced use of templates is to recursively expand + them, relying on specialization to end it. A template + to compute a factorial would be: + +

+
+

+	template<int n> class factorial
+	{
+	    public:
+		enum { result = n * factorial<n - 1>::result }; 
+	};
+
+	template<> class factorial<1>
+	{
+	    public:
+		enum { result = 1 };
+	};
+
+	void test()
+	{
+	    printf("%d\n", factorial<4>::result); // prints 24
+	}

+ +

The D Way

+ + The D version is analogous, though a little simpler, taking + advantage of promotion of single template members to the + enclosing name space: + +

+
+

+	template factorial(int n)
+	{
+	    enum { factorial = n* .factorial!(n-1) }
+	}
+
+	template factorial(int n : 1)
+	{
+	    enum { factorial = 1 }
+	}
+
+	void test()
+	{
+	    printf("%d\n", factorial!(4));	// prints 24 
+	}

+ +


+ + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/ctod.html dmd-0.124/dmd/html/d/ctod.html --- dmd-0.123/dmd/html/d/ctod.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/ctod.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,1489 +1,1747 @@ - - - - -Digital Mars - Programming in D for C Programmers - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Sep 16, 2004 -


- -

Programming in D for C Programmers

- -ouch! - -Every experienced C programmer accumulates a series of idioms and techniques -which become second nature. Sometimes, when learning a new language, those -idioms can be so comfortable it's hard to see how to do the equivalent in the -new language. So here's a collection of common C techniques, and how to do the -corresponding task in D. -

- -Since C does not have object-oriented features, there's a separate section -for object-oriented issues -Programming in D for C++ Programmers. -

- -The C preprocessor is covered in -The C Preprocessor vs D. - -

- -
-

Getting the Size of a Type

- -

The C Way

- -
-	sizeof(int)
-	sizeof(char *)
-	sizeof(double)
-	sizeof(struct Foo)
-
- -

The D Way

- -

Use the size property:

- -
-        int.size
-        (char *).size
-        double.size
-        Foo.size
-
- -
- -

Get the max and min values of a type

- -

The C Way

- -
-	#include <limits.h>
-	#include <math.h>
-
-	CHAR_MAX
-	CHAR_MIN
-	ULONG_MAX
-	DBL_MIN
-
- -

The D Way

- -
-        char.max
-        char.min
-        ulong.max
-        double.min
-
- -
- -

Primitive Types

- -

C to D types

- -
-        bool               =>        bit 
-        char               =>        char 
-        signed char        =>        byte 
-        unsigned char      =>        ubyte 
-        short              =>        short 
-        unsigned short     =>        ushort 
-        wchar_t            =>        wchar 
-        int                =>        int 
-        unsigned           =>        uint 
-        long               =>        int 
-        unsigned long      =>        uint 
-        long long          =>        long 
-        unsigned long long =>        ulong 
-        float              =>        float 
-        double             =>        double 
-        long double        =>        real 
-	_Imaginary long double =>    imaginary
-	_Complex long double   =>    complex
-
-
-

- Although char is an unsigned 8 bit type, and - wchar is an unsigned 16 bit type, they have their own separate types - in order to aid overloading and type safety. -

- Ints and unsigneds in C are of varying size; not so in D. - -


- -

Special Floating Point Values

- -

The C Way

- -
-       #include <fp.h> 
-
-       NAN 
-       INFINITY 
-
-       #include <float.h> 
-
-       DBL_DIG 
-       DBL_EPSILON 
-       DBL_MANT_DIG 
-       DBL_MAX_10_EXP 
-       DBL_MAX_EXP 
-       DBL_MIN_10_EXP 
-       DBL_MIN_EXP 
-
-

The D Way

-
-       double.nan 
-       double.infinity 
-       double.dig 
-       double.epsilon 
-       double.mant_dig 
-       double.max_10_exp 
-       double.max_exp 
-       double.min_10_exp 
-       double.min_exp 
-
- -
-

Remainder after division of floating point numbers

- -

The C Way

-
-       #include <math.h> 
-
-       float f = fmodf(x,y); 
-       double d = fmod(x,y); 
-       long double e = fmodl(x,y); 
-
-

The D Way

-

-D supports the remainder ('%') operator on floating point operands: -

-       float f = x % y; 
-       double d = x % y; 
-       extended e = x % y; 
-
- -
- -

Dealing with NAN's in floating point compares

- -

The C Way

-

- C doesn't define what happens if an operand to a compare - is NAN, and few C compilers check for it (the Digital Mars - C compiler is an exception, DM's compilers do check for NAN operands). -

-       #include <math.h> 
-
-       if (isnan(x) || isnan(y)) 
-	   result = FALSE; 
-       else 
-	   result = (x < y); 
-
-

The D Way

-

- D offers a full complement of comparisons and operators - that work with NAN arguments. -

-       result = (x < y);        // false if x or y is nan 
-
- -
- -

Assert's are a necessary part of any good defensive coding strategy.

- -

The C Way

-

-C doesn't directly support assert, but does support __FILE__ -and __LINE__ from which an assert macro can be built. In fact, -there appears to be practically no other use for __FILE__ and __LINE__. - -

-       #include <assert.h> 
-
-       assert(e == 0); 
-
-

The D Way

-

-D simply builds assert into the language: -

-       assert(e == 0); 
-
-

-[NOTE: trace functions?] - -


- -

Initializing all elements of an array

- -

The C Way

-
-       #define ARRAY_LENGTH        17 
-       int array[ARRAY_LENGTH]; 
-       for (i = 0; i < ARRAY_LENGTH; i++) 
-	   array[i] = value; 
-
-

The D Way

-
-       int array[17]; 
-       array[] = value; 
-
- -
- -

Looping through an array

- -

The C Way

-

- The array length is defined separately, or a clumsy - sizeof() expression is used to get the length. -

-       #define ARRAY_LENGTH        17 
-       int array[ARRAY_LENGTH]; 
-       for (i = 0; i < ARRAY_LENGTH; i++) 
-	   func(array[i]); 
-
-or: -
-       int array[17]; 
-       for (i = 0; i < sizeof(array) / sizeof(array[0]); i++) 
-	   func(array[i]); 
-
-

The D Way

-

-The length of an array is accessible the property "length". -

-       int array[17]; 
-       for (i = 0; i < array.length; i++) 
-	   func(array[i]); 
-
-or even better: -
-       int array[17]; 
-       foreach (int value; array)
-	   func(value); 
-
- - -
- -

Creating an array of variable size

- -

The C Way

- - C cannot do this with arrays. It is necessary to create a separate - variable for the length, and then explicitly manage the size of - the array: - -
-               #include <stdlib.h> 
-
-               int array_length; 
-               int *array; 
-               int *newarray; 
-
-               newarray = (int *) realloc(array, (array_length + 1) * sizeof(int)); 
-               if (!newarray) 
-                   error("out of memory"); 
-               array = newarray; 
-               array[array_length++] = x; 
-
- -

The D Way

- - D supports dynamic arrays, which can be easily resized. D supports - all the requisite memory management. -
-               int[] array; 
-
-               array.length = array.length + 1;
-               array[array.length - 1] = x; 
-
-
- -

String Concatenation

- -

The C Way

-

- There are several difficulties to be resolved, like - when can storage be free'd, dealing with null pointers, - finding the length of the strings, and memory allocation: - -

 
-               #include <string.h> 
-
-               char *s1; 
-               char *s2; 
-               char *s; 
-
-               // Concatenate s1 and s2, and put result in s 
-               free(s); 
-               s = (char *)malloc((s1 ? strlen(s1) : 0) + 
-                                  (s2 ? strlen(s2) : 0) + 1); 
-               if (!s) 
-                   error("out of memory"); 
-               if (s1) 
-                   strcpy(s, s1); 
-               else 
-                   *s = 0; 
-               if (s2) 
-                   strcpy(s + strlen(s), s2); 
-
-               // Append "hello" to s 
-               char hello[] = "hello"; 
-               char *news; 
-               size_t lens = s ? strlen(s) : 0; 
-               news = (char *)realloc(s, (lens + sizeof(hello) + 1) * sizeof(char)); 
-               if (!news) 
-                   error("out of memory"); 
-               s = news; 
-               memcpy(s + lens, hello, sizeof(hello)); 
-
-

The D Way

- - D overloads the operators ~ and ~= for char and wchar arrays to mean - concatenate and append, respectively: -
-               char[] s1; 
-               char[] s2; 
-               char[] s; 
-
-               s = s1 ~ s2; 
-               s ~= "hello"; 
-
-
- -

Formatted printing

- -

The C Way

- - printf() is the general purpose formatted print routine: -
-               #include <stdio.h> 
-
-               printf("Calling all cars %d times!\n", ntimes); 
-
-

The D Way

- - What can we say? printf() rules: -
-               import stdio; 
-
-               printf("Calling all cars %d times!\n", ntimes); 
-
-
- -

Forward referencing functions

- -

The C Way

- - Functions cannot be forward referenced. Hence, to call a function - not yet encountered in the source file, it is necessary to insert - a function declaration lexically preceding the call. -
-               void forwardfunc(); 
-
-               void myfunc() 
-               { 
-                   forwardfunc(); 
-               } 
-
-               void forwardfunc() 
-               { 
-                   ... 
-               } 
-
-

The D Way

- - The program is looked at as a whole, and so not only is it not - necessary to code forward declarations, it is not even allowed! - D avoids the tedium and errors associated with writing forward - referenced function declarations twice. - Functions can be defined in any order. -
-               void myfunc() 
-               { 
-                   forwardfunc(); 
-               } 
-
-               void forwardfunc() 
-               { 
-                   ... 
-               } 
-
-
- -

Functions that have no arguments

- -

The C Way

-
-               void function(void); 
-
-

The D Way

- - D is a strongly typed language, so there is no need to explicitly - say a function takes no arguments, just don't declare it has having - arguments. -
-               void function() 
-               { 
-                   ... 
-               } 
-
-
- -

Labelled break's and continue's.

- -

The C Way

- - Break's and continue's only apply to the innermost nested loop or - switch, so a multilevel break must use a goto: -
-               for (i = 0; i < 10; i++) 
-               { 
-                   for (j = 0; j < 10; j++) 
-                   { 
-                       if (j == 3) 
-                           goto Louter; 
-                       if (j == 4) 
-                           goto L2; 
-                   } 
-                 L2: 
-                   ; 
-               } 
-           Louter: 
-               ; 
-
-

The D Way

- - Break and continue statements can be followed by a label. The label - is the label for an enclosing loop or switch, and the break applies - to that loop. -
-             Louter: 
-               for (i = 0; i < 10; i++) 
-               { 
-                   for (j = 0; j < 10; j++) 
-                   { 
-                       if (j == 3) 
-                           break Louter; 
-                       if (j == 4) 
-                           continue Louter; 
-                   } 
-               } 
-               // break Louter goes here 
-
-
- -

Goto Statements

- -

The C Way

- - The much maligned goto statement is a staple for professional C coders. It's - necessary to make up for sometimes inadequate control flow statements. - -

The D Way

- - Many C-way goto statements can be eliminated with the D feature of labelled - break and continue statements. But D is a practical language for practical - programmers who know when the rules need to be broken. So of course D supports - the goto! - -
-

Struct tag name space

- -

The C Way

- - It's annoying to have to put the struct keyword every time a type is specified, - so a common idiom is to use: -
-               typedef struct ABC { ... } ABC; 
-
-

The D Way

- - Struct tag names are not in a separate name space, they are in the same name - space as ordinary names. Hence: -
-               struct ABC { ... }; 
-
- -
- -

Looking up strings

- -

The C Way

- - Given a string, compare the string against a list of possible - values and take action based on which one it is. A typical use - for this might be command line argument processing. -
-               #include <string.h> 
-               void dostring(char *s) 
-               { 
-                   enum Strings { Hello, Goodbye, Maybe, Max }; 
-                   static char *table[] = { "hello", "goodbye", "maybe" }; 
-                   int i; 
-
-                   for (i = 0; i < Max; i++) 
-                   { 
-                       if (strcmp(s, table[i]) == 0) 
-                           break; 
-                   } 
-                   switch (i) 
-                   { 
-                       case Hello:        ... 
-                       case Goodbye:        ... 
-                       case Maybe:        ... 
-                       default:        ... 
-                   } 
-               } 
-
- The problem with this is trying to maintain 3 parallel data - structures, the enum, the table, and the switch cases. If there - are a lot of values, the connection between the 3 may not be so - obvious when doing maintenance, and so the situation is ripe for - bugs. - - Additionally, if the number of values becomes large, a binary or - hash lookup will yield a considerable performance increase over - a simple linear search. But coding these can be time consuming, - and they need to be debugged. It's typical that such just never - gets done. - -

The D Way

- - D extends the concept of switch statements to be able to handle - strings as well as numbers. Then, the way to code the string - lookup becomes straightforward: -
-               void dostring(char[] s) 
-               { 
-                   switch (s) 
-                   { 
-                       case "hello":        ... 
-                       case "goodbye":        ... 
-                       case "maybe":        ... 
-                       default:        ... 
-                   } 
-               } 
-
- Adding new cases becomes easy. The compiler can be relied on - to generate a fast lookup scheme for it, eliminating the bugs - and time required in hand-coding one. - -
- -

Setting struct member alignment

- -

The C Way

- - It's done through a command line switch which affects the entire - program, and woe results if any modules or libraries didn't get - recompiled. To address this, #pragma's are used: -
-           #pragma pack(1) 
-           struct ABC 
-           { 
-               ... 
-           }; 
-           #pragma pack() 
-
- But #pragmas are nonportable both in theory and in practice from - compiler to compiler. - -

The D Way

- - Clearly, since much of the point to setting alignment is for - portability of data, a portable means of expressing it is necessary. -
-           struct ABC 
-           { 
-               int z;                     // z is aligned to the default 
-
-             align (1) int x;             // x is byte aligned 
-             align (4) 
-             { 
-               ...                        // declarations in {} are dword aligned 
-             } 
-             align (2):                   // switch to word alignment from here on 
-
-               int y;                     // y is word aligned 
-           } 
-
-
- -

Anonymous Structs and Unions

- -Sometimes, it's nice to control the layout of a struct with nested structs and unions. - -

The C Way

- - C doesn't allow anonymous structs or unions, which means that dummy tag names - and dummy members are necessary: -
-           struct Foo 
-           {   int i; 
-               union Bar 
-               { 
-                   struct Abc { int x; long y; } _abc; 
-                   char *p; 
-               } _bar; 
-           }; 
-
-           #define x _bar._abc.x 
-           #define y _bar._abc.y 
-           #define p _bar.p 
-
-           struct Foo f; 
-
-           f.i; 
-           f.x; 
-           f.y; 
-           f.p; 
-
- Not only is it clumsy, but using macros means a symbolic debugger won't understand - what is being done, and the macros have global scope instead of struct scope. - -

The D Way

- - Anonymous structs and unions are used to control the layout in a - more natural manner: -
-           struct Foo 
-           {   int i; 
-               union 
-               { 
-                   struct { int x; long y; } 
-                   char* p; 
-               } 
-           } 
-
-           Foo f; 
-
-           f.i; 
-           f.x; 
-           f.y; 
-           f.p; 
-
- -
- -

Declaring struct types and variables.

- -

The C Way

- - Is to do it in one statement ending with a semicolon: -
-           struct Foo { int x; int y; } foo; 
-
- Or to separate the two: -
-           struct Foo { int x; int y; };        // note terminating ; 
-           struct Foo foo; 
-
-

The D Way

- - Struct definitions and declarations can't be done in the same statement: -
-           struct Foo { int x; int y; }        // note there is no terminating ; 
-           Foo foo; 
-
- which means that the terminating ; can be dispensed with, eliminating the - confusing difference between struct {} and function & block {} in how semicolons - are used. - -
- -

Getting the offset of a struct member.

- -

The C Way

- - Naturally, another macro is used: -
-           #include <stddef> 
-           struct Foo { int x; int y; }; 
-
-           off = offsetof(Foo, y); 
-
-

The D Way

- - An offset is just another property: -
-           struct Foo { int x; int y; } 
-
-           off = Foo.y.offset; 
-
- -
- -

Union initializations.

- -

The C Way

- - Unions are initialized using the "first member" rule: -
-           union U { int a; long b; }; 
-           union U x = { 5 };                // initialize member 'a' to 5 
-
- Adding union members or rearranging them can have disastrous consequences - for any initializers. - -

The D Way

- - In D, which member is being initialized is mentioned explicitly: -
-           union U { int a; long b; } 
-           U x = { a:5 } 
-
- avoiding the confusion and maintenance problems. - -
- -

Struct initializations.

- -

The C Way

- - Members are initialized by their position within the {}'s: -
-           struct S { int a; int b; }; 
-           struct S x = { 5, 3 }; 
-
- This isn't much of a problem with small structs, but when there - are numerous members, it becomes tedious to get the initializers - carefully lined up with the field declarations. Then, if members are - added or rearranged, all the initializations have to be found and - modified appropriately. This is a minefield for bugs. - -

The D Way

- - Member initialization can be done explicitly: -
-           struct S { int a; int b; } 
-           S x = { b:3, a:5 } 
-
- The meaning is clear, and there no longer is a positional dependence. - -
- -

Array initializations.

- -

The C Way

- - C initializes array by positional dependence: -
-           int a[3] = { 3,2,2 }; 
-
- Nested arrays may or may not have the { }: -
-           int b[3][2] = { 2,3, {6,5}, 3,4 }; 
-
-

The D Way

- - D does it by positional dependence too, but an index can be used as well: - The following all produce the same result: -
-    int[3] a = [ 3, 2, 0 ]; 
-    int[3] a = [ 3, 2 ];              // unsupplied initializers are 0, just like in C 
-    int[3] a = [ 2:0, 0:3, 1:2 ]; 
-    int[3] a = [ 2:0, 0:3, 2 ];       // if not supplied, the index is the previous 
-			              // one plus one. 
-
- This can be handy if the array will be indexed by an enum, and the order of - enums may be changed or added to: -
-    enum color { black, red, green }
-    int[3] c = [ black:3, green:2, red:5 ]; 
-
- Nested array initializations must be explicit: -
-    int[2][3] b = [ [2,3], [6,5], [3,4] ]; 
-
-    int[2][3] b = [[2,6,3],[3,5,4]];            // error 
-
- -
- -

Escaped String Literals

- -

The C Way

- - C has problems with the DOS file system because a \ is an escape in a string. To specifiy file c:\root\file.c: -
-    char file[] = "c:\\root\\file.c"; 
-
-This gets even more unpleasant with regular expressions. -Consider the escape sequence to match a quoted string: -
-    /"[^\\]*(\\.[^\\]*)*"/
-
-

In C, this horror is expressed as: -

-    char quoteString[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\"";
-
-

The D Way

- - Within strings, it is WYSIWYG (what you see is what you get). - Escapes are in separate strings. So: -
-    char[] file = 'c:\root\file.c'; 
-    char[] quoteString = \"  r"[^\\]*(\\.[^\\]*)*"  \";
-
- The famous hello world string becomes: -
-    char[] hello = "hello world" \n; 
-
- -
- -

Ascii vs Wide Characters

- -

Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs. - -

The C Way

- - C uses the wchar_t and the L prefix on strings: -
-    #include <wchar.h> 
-    char foo_ascii[] = "hello"; 
-    wchar_t foo_wchar[] = L"hello"; 
-
-Things get worse if code is written to be both ascii and wchar compatible. -A macro is used to switch strings from ascii to wchar: -
-    #include <tchar.h> 
-    tchar string[] = TEXT("hello"); 
-
-

The D Way

- -The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call: -
-    char[] foo_ascii = "hello";            // string is taken to be ascii 
-    wchar[] foo_wchar = "hello";       // string is taken to be wchar 
-
- -
- -

Arrays that parallel an enum

- -

The C Way

- - Consider: -
-       enum COLORS { red, blue, green, max }; 
-       char *cstring[max] = {"red", "blue", "green" }; 
-
- This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added. - -

The D Way

-
-   enum COLORS { red, blue, green }
-
-    char[][COLORS.max + 1] cstring = 
-    [
-	COLORS.red   : "red",
-	COLORS.blue  : "blue", 
-	COLORS.green : "green",
-    ]; 
-
- -Not perfect, but better. - -
- -

Creating a new typedef'd type

- -

The C Way

- - Typedef's in C are weak, that is, they really do not introduce - a new type. The compiler doesn't distinguish between a typedef - and its underlying type. - -
-	typedef void *Handle;
-	void foo(void *);
-	void bar(Handle);
-
-	Handle h;
-	foo(h);			// coding bug not caught
-	bar(h);			// ok
-	
- - The C solution is to create a dummy struct whose sole - purpose is to get type checking and overloading on the new type. - -
-	struct Handle__ { void *value; }
-	typedef struct Handle__ *Handle;
-	void foo(void *);
-	void bar(Handle);
-
-	Handle h;
-	foo(h);			// syntax error
-	bar(h);			// ok
-	
- - Having a default value for the type involves defining a macro, - a naming convention, and then pedantically following that convention: - -
-	#define HANDLE_INIT ((Handle)-1)
-
-	Handle h = HANDLE_INIT;
-	h = func();
-	if (h != HANDLE_INIT)
-	    ...
-	
- - For the struct solution, things get even more complex: - -
-	struct Handle__ HANDLE_INIT;
-
-	void init_handle()	// call this function upon startup
-	{
-	    HANDLE_INIT.value = (void *)-1;
-	}
-
-	Handle h = HANDLE_INIT;
-	h = func();
-	if (memcmp(&h,&HANDLE_INIT,sizeof(Handle)) != 0)
-	    ...
-	
- - There are 4 names to remember: Handle, HANDLE_INIT, - struct Handle__, value. - -

The D Way

- - No need for idiomatic constructions like the above. Just write: - -
-	typedef void* Handle;
-	void foo(void*);
-	void bar(Handle);
-
-	Handle h;
-	foo(h);
-	bar(h);
-	
- - To handle a default value, add an initializer to the typedef, - and refer to it with the .init property: - -
-	typedef void* Handle = cast(void*)(-1);
-	Handle h;
-	h = func();
-	if (h != Handle.init)
-	    ...
-	
- - There's only one name to remember: Handle. - -
- -

Comparing structs

- -

The C Way

- - While C defines struct assignment in a simple, convenient manner: - -
-	struct A x, y;
-	...
-	x = y;
-	
- - it does not for struct comparisons. Hence, to compare two struct - instances for equality: - -
-	#include <string.h>
-
-	struct A x, y;
-	...
-	if (memcmp(&x, &y, sizeof(struct A)) == 0)
-	    ...
-	
- - Note the obtuseness of this, coupled with the lack of any kind - of help from the language with type checking. -

- - There's a nasty bug lurking in the memcmp(). - The layout of a struct, due to alignment, can have 'holes' in it. - C does not guarantee those holes are assigned any values, and so - two different struct instances can have the same value for each member, - but compare different because the holes contain different garbage. - -

The D Way

- - D does it the obvious, straightforward way: - -
-	A x, y;
-	...
-	if (x == y)
-	    ...
-	
- - -
-

Comparing strings

- -

The C Way

- - The library function strcmp() is used: -
-	char string[] = "hello";
-
-	if (strcmp(string, "betty") == 0)	// do strings match?
-	    ...
-	
- - C uses 0 terminated strings, so the C way has an inherent - inefficiency in constantly scanning for the terminating 0. - -

The D Way

- - Why not use the == operator? - -
-	char[] string = "hello";
-
-	if (string == "betty")
-	    ...
-	
- - D strings have the length stored separately from the string. - Thus, the implementation of string compares can be much faster - than in C (the difference being equivalent to the difference - in speed between the C memcmp() and strcmp()). -

- - D supports comparison operators on strings, too: - -

-	char[] string = "hello";
-
-	if (string < "betty")
-	    ...
-	
- - which is useful for sorting/searching. - -
-

Sorting arrays

- -

The C Way

- - Although many C programmers tend to reimplmement bubble sorts - over and over, the right way to sort in C is to use qsort(): - -
-	int compare(const void *p1, const void *p2)
-	{
-	    type *t1 = (type *)p1;
-	    type *t1 = (type *)p2;
-
-	    return *t1 - *t2;
-	}
-
-	type array[10];
-	...
-	qsort(array, sizeof(array)/sizeof(array[0]), sizeof(array[0]), compare);
-	
- - A compare() must be written for each type, and much careful - typo-prone code needs to be written to make it work. - - -

The D Way

- - Sorting couldn't be easier: - -
-	type[] array;
-	...
-	array.sort;		// sort array in-place
-	
- -
-

Volatile memory access

- -

The C Way

- - To access volatile memory, such as shared memory - or memory mapped I/O, a pointer to volatile is created: -
-	volatile int *p = address;
-
-	i = *p;
-	
- -

The D Way

- - D has volatile as a statement type, not as a type modifier: - -
-	int* p = address;
-
-	volatile { i = *p; }
-	
- -
-

String literals

- -

The C Way

- - String literals in C cannot span multiple lines, so to have - a block of text it is necessary to use \ line splicing: - -
-	"This text spans\n\
-	multiple\n\
-	lines\n"
-	
- - If there is a lot of text, this can wind up being tedious. - -

The D Way

- - String literals can span multiple lines, as in: - -
-	"This text spans
-	multiple
-	lines
-	"
-	
- - So blocks of text can just be cut and pasted into the D - source. - -
-

Data Structure Traversal

- -

The C Way

- - Consider a function to traverse a recursive data structure. - In this example, there's a simple symbol table of strings. - The data structure is an array of binary trees. - The code needs to do an exhaustive search of it to find - a particular string in it, and determine if it is a unique - instance. -

- - To make this work, a helper function membersearchx - is needed to recursively - walk the trees. The helper function needs to read and write - some context outside of the trees, so a custom struct Paramblock - is created and a pointer to it is used to maximize efficiency. - -

-    struct Symbol
-    {	char *id;
-	struct Symbol *left;
-	struct Symbol *right;
-    };
-
-    struct Paramblock
-    {   char *id;
-	struct Symbol *sm;
-    };
-
-    static void membersearchx(struct Paramblock *p, struct Symbol *s)
-    {
-	while (s)
-	{
-	    if (strcmp(p->id,s->id) == 0)
-	    {
-		if (p->sm)
-		    error("ambiguous member %s\n",p->id);
-		p->sm = s;
-	    }
-
-	    if (s->left)
-		membersearchx(p,s->left);
-	    s = s->right;
-	}
-    }
-
-    struct Symbol *symbol_membersearch(Symbol *table[], int tablemax, char *id)
-    {
-	struct Paramblock pb;
-	int i;
-
-	pb.id = id;
-	pb.sm = NULL;
-	for (i = 0; i < tablemax; i++)
-	{
-	    membersearchx(pb, table[i]);
-	}
-	return pb.sm;
-    }
-    
- -

The D Way

- - This is the same algorithm in D, and it shrinks dramatically. - Since nested functions have access to the lexically enclosing - function's variables, there's no need for a Paramblock or - to deal with its bookkeeping details. The nested helper function - is contained wholly within the function that needs it, - improving locality and maintainability. -

- - The performance of the two versions is indistinguishable. - -

-    class Symbol
-    {	char[] id;
-	Symbol left;
-	Symbol right;
-    }
-
-    Symbol symbol_membersearch(Symbol[] table, char[] id)
-    {   Symbol sm;
-
-	void membersearchx(Symbol s)
-	{
-	    while (s)
-	    {
-		if (id == s.id)
-		{
-		    if (sm)
-			error("ambiguous member %s\n", id);
-		    sm = s;
-		}
-
-		if (s.left)
-		    membersearchx(s.left);
-		s = s.right;
-	    }
-	}
-
-	for (int i = 0; i < table.length; i++)
-	{
-	    membersearchx(table[i]);
-	}
-	return sm;
-    }
-    
- -
-

Unsigned Right Shift

- -

The C Way

- - The right shift operators >> and >>= are signed - shifts if the left operand is a signed integral type, and - are unsigned right shifts if the left operand is an unsigned - integral type. To produce an unsigned right shift on an int, - a cast is necessary: - -
-	int i, j;
-	...
-	j = (unsigned)i >> 3;
-	
- - If i is an int, this works fine. But if i is - of a typedef'd type, - -
-	myint i, j;
-	...
-	j = (unsigned)i >> 3;
-	
- - and myint happens to be a long int, then the cast to - unsigned - will silently throw away the most significant bits, corrupting - the answer. - -

The D Way

- - D has the right shift operators >> and >>= which - behave as they do in C. But D also has explicitly unsigned - right shift operators >>> and >>>= which will - do an unsigned right shift regardless of the sign of the left - operand. Hence, - -
-	myint i, j;
-	...
-	j = i >>> 3;
-	
- - avoids the unsafe cast and will work as expected with any integral - type. - -
-

Dynamic Closures

- -

The C Way

- - Consider a reusable container type. In order to be reusable, - it must support a way to apply arbitrary code to each element - of the container. This is done by creating an apply function - that accepts a function pointer to which is passed each - element of the container contents. -

- - A generic context pointer is also needed, represented here by - void *p. The example here is of a trivial container - class that holds an array of int's, and a user of that container - that computes the maximum of those int's. - -

-	struct Collection
-	{
-	    int array[10];
-
-	    void apply(void *p, void (*fp)(void *, int))
-	    {
-		for (int i = 0; i < sizeof(array)/sizeof(array[0]); i++)
-		    fp(p, array[i]);
-	    }
-	};
-
-	void comp_max(void *p, int i)
-	{
-	    int *pmax = (int *)p;
-
-	    if (i > *pmax)
-		*pmax = i;
-	}
-
-	void func(Collection *c)
-	{
-	    int max = INT_MIN;
-
-	    c->apply(&max, comp_max);
-	}
-	
- - The C way makes heavy use of pointers and casting. - The casting is tedious, error prone, and loses all type safety. - -

The D Way

- - The D version makes use of delegates to transmit - context information for the apply function, - and nested functions both to capture context - information and to improve locality. - -

- -
-
	class Collection
-	{
-	    int[10] array;
-
-	    void apply(void delegate(int) fp)
-	    {
-		for (int i = 0; i < array.length; i++)
-		    fp(array[i]);
-	    }
-	}
-
-	void func(Collection c)
-	{
-	    int max = int.min;
-
-	    void comp_max(int i)
-	    {
-		if (i > max)
-		    max = i;
-	    }
-
-	    c.apply(comp_max);
-	}

- - Pointers are eliminated, as well as casting and generic - pointers. The D version is fully type safe. - An alternate method in D makes use of function literals: - -

- -
-
	void func(Collection c)
-	{
-	    int max = int.min;
-
-	    c.apply(delegate(int i) { if (i > max) max = i; } );
-	}

- - eliminating the need to create irrelevant function names. - - -

Feedback and Comments

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

- - - + + + + + + + + + + + + + + + + + + + + + +Digital Mars - Programming in D for C Programmers + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

Programming in D for C Programmers

+ +ouch! + +Every experienced C programmer accumulates a series of idioms and techniques +which become second nature. Sometimes, when learning a new language, those +idioms can be so comfortable it's hard to see how to do the equivalent in the +new language. So here's a collection of common C techniques, and how to do the +corresponding task in D. +

+ +Since C does not have object-oriented features, there's a separate section +for object-oriented issues +Programming in D for C++ Programmers. +

+ +The C preprocessor is covered in +The C Preprocessor vs D. + +

+ +
+

Getting the Size of a Type

+ +

The C Way

+ +

+
+
	sizeof(int)
+	sizeof(char *)
+	sizeof(double)
+	sizeof(struct Foo)

+ +

The D Way

+ +

Use the size property:

+ +

+
+
        int.size
+        (char *).size
+        double.size
+        Foo.size

+ +


+ +

Get the max and min values of a type

+ +

The C Way

+ +

+
+
	#include <limits.h>
+	#include <math.h>
+
+	CHAR_MAX
+	CHAR_MIN
+	ULONG_MAX
+	DBL_MIN
+

+ +

The D Way

+ +

+
+
        char.max
+        char.min
+        ulong.max
+        double.min
+

+ +


+ +

Primitive Types

+ +

C to D types

+ +

+
+
        bool               =>        bit 
+        char               =>        char 
+        signed char        =>        byte 
+        unsigned char      =>        ubyte 
+        short              =>        short 
+        unsigned short     =>        ushort 
+        wchar_t            =>        wchar 
+        int                =>        int 
+        unsigned           =>        uint 
+        long               =>        int 
+        unsigned long      =>        uint 
+        long long          =>        long 
+        unsigned long long =>        ulong 
+        float              =>        float 
+        double             =>        double 
+        long double        =>        real 
+	_Imaginary long double =>    imaginary
+	_Complex long double   =>    complex
+
+

+

+ Although char is an unsigned 8 bit type, and + wchar is an unsigned 16 bit type, they have their own separate types + in order to aid overloading and type safety. +

+ Ints and unsigneds in C are of varying size; not so in D. + +


+ +

Special Floating Point Values

+ +

The C Way

+ +

+
+
       #include <fp.h> 
+
+       NAN 
+       INFINITY 
+
+       #include <float.h> 
+
+       DBL_DIG 
+       DBL_EPSILON 
+       DBL_MANT_DIG 
+       DBL_MAX_10_EXP 
+       DBL_MAX_EXP 
+       DBL_MIN_10_EXP 
+       DBL_MIN_EXP 
+

+ +

The D Way

+ +

+
+
       double.nan 
+       double.infinity 
+       double.dig 
+       double.epsilon 
+       double.mant_dig 
+       double.max_10_exp 
+       double.max_exp 
+       double.min_10_exp 
+       double.min_exp 
+

+ +


+

Remainder after division of floating point numbers

+ +

The C Way

+ +

+
+

+       #include <math.h> 
+
+       float f = fmodf(x,y); 
+       double d = fmod(x,y); 
+       long double e = fmodl(x,y); 
+

+ +

The D Way

+ +D supports the remainder ('%') operator on floating point operands: + +

+
+

+       float f = x % y; 
+       double d = x % y; 
+       extended e = x % y; 
+

+ +


+ +

Dealing with NAN's in floating point compares

+ +

The C Way

+ + C doesn't define what happens if an operand to a compare + is NAN, and few C compilers check for it (the Digital Mars + C compiler is an exception, DM's compilers do check for NAN operands). + +

+
+

+       #include <math.h> 
+
+       if (isnan(x) || isnan(y)) 
+	   result = FALSE; 
+       else 
+	   result = (x < y); 
+

+ +

The D Way

+

+ D offers a full complement of comparisons and operators + that work with NAN arguments. + +

+
+
       result = (x < y);        // false if x or y is nan 
+

+ +


+ +

Assert's are a necessary part of any good defensive coding strategy.

+ +

The C Way

+

+C doesn't directly support assert, but does support __FILE__ +and __LINE__ from which an assert macro can be built. In fact, +there appears to be practically no other use for __FILE__ and __LINE__. + +

+
+

+       #include <assert.h> 
+
+       assert(e == 0); 
+

+ +

The D Way

+ +D simply builds assert into the language: + +

+
+

+       assert(e == 0); 
+

+ +[NOTE: trace functions?] + +


+ +

Initializing all elements of an array

+ +

The C Way

+ +

+
+

+       #define ARRAY_LENGTH        17 
+       int array[ARRAY_LENGTH]; 
+       for (i = 0; i < ARRAY_LENGTH; i++) 
+	   array[i] = value; 
+

+ +

The D Way

+ +

+
+

+       int array[17]; 
+       array[] = value; 
+

+ +


+ +

Looping through an array

+ +

The C Way

+

+ The array length is defined separately, or a clumsy + sizeof() expression is used to get the length. + +

+
+

+       #define ARRAY_LENGTH        17 
+       int array[ARRAY_LENGTH]; 
+       for (i = 0; i < ARRAY_LENGTH; i++) 
+	   func(array[i]); 
+

+ +or: + +

+
+

+       int array[17]; 
+       for (i = 0; i < sizeof(array) / sizeof(array[0]); i++) 
+	   func(array[i]); 
+

+ +

The D Way

+ +The length of an array is accessible the property "length". + +

+
+

+       int array[17]; 
+       for (i = 0; i < array.length; i++) 
+	   func(array[i]); 
+

+ +or even better: + +

+
+

+       int array[17]; 
+       foreach (int value; array)
+	   func(value); 
+

+ + +


+ +

Creating an array of variable size

+ +

The C Way

+ + C cannot do this with arrays. It is necessary to create a separate + variable for the length, and then explicitly manage the size of + the array: + +

+
+

+       #include <stdlib.h> 
+
+       int array_length; 
+       int *array; 
+       int *newarray; 
+
+       newarray = (int *)
+	   realloc(array, (array_length + 1) * sizeof(int)); 
+       if (!newarray) 
+	   error("out of memory"); 
+       array = newarray; 
+       array[array_length++] = x; 
+

+ +

The D Way

+ + D supports dynamic arrays, which can be easily resized. D supports + all the requisite memory management. + +

+
+

+       int[] array; 
+
+       array.length = array.length + 1;
+       array[array.length - 1] = x; 
+

+ +


+ +

String Concatenation

+ +

The C Way

+ + There are several difficulties to be resolved, like + when can storage be free'd, dealing with null pointers, + finding the length of the strings, and memory allocation: + +

+
+
 
+       #include <string.h> 
+
+       char *s1; 
+       char *s2; 
+       char *s; 
+
+       // Concatenate s1 and s2, and put result in s 
+       free(s); 
+       s = (char *)malloc((s1 ? strlen(s1) : 0) + 
+			  (s2 ? strlen(s2) : 0) + 1); 
+       if (!s) 
+	   error("out of memory"); 
+       if (s1) 
+	   strcpy(s, s1); 
+       else 
+	   *s = 0; 
+       if (s2) 
+	   strcpy(s + strlen(s), s2); 
+
+       // Append "hello" to s 
+       char hello[] = "hello"; 
+       char *news; 
+       size_t lens = s ? strlen(s) : 0; 
+       news = (char *)
+	   realloc(s, (lens + sizeof(hello) + 1) * sizeof(char)); 
+       if (!news) 
+	   error("out of memory"); 
+       s = news; 
+       memcpy(s + lens, hello, sizeof(hello)); 
+

+ +

The D Way

+ + D overloads the operators ~ and ~= for char and wchar arrays to mean + concatenate and append, respectively: + +

+
+

+       char[] s1; 
+       char[] s2; 
+       char[] s; 
+
+       s = s1 ~ s2; 
+       s ~= "hello"; 
+

+ +


+ +

Formatted printing

+ +

The C Way

+ + printf() is the general purpose formatted print routine: + +

+
+

+       #include <stdio.h> 
+
+       printf("Calling all cars %d times!\n", ntimes); 
+

+ +

The D Way

+ + What can we say? printf() rules: + +

+
+

+       import stdio; 
+
+       printf("Calling all cars %d times!\n", ntimes); 
+

+ +


+ +

Forward referencing functions

+ +

The C Way

+ + Functions cannot be forward referenced. Hence, to call a function + not yet encountered in the source file, it is necessary to insert + a function declaration lexically preceding the call. + +

+
+

+       void forwardfunc(); 
+
+       void myfunc() 
+       {   
+	   forwardfunc(); 
+       } 
+
+       void forwardfunc() 
+       {   
+	   ... 
+       } 
+

+ +

The D Way

+ + The program is looked at as a whole, and so not only is it not + necessary to code forward declarations, it is not even allowed! + D avoids the tedium and errors associated with writing forward + referenced function declarations twice. + Functions can be defined in any order. + +

+
+

+        void myfunc() 
+        {   
+	   forwardfunc(); 
+        } 
+
+        void forwardfunc() 
+        {   
+	   ... 
+        } 
+

+ +


+ +

Functions that have no arguments

+ +

The C Way

+ +

+
+

+       void function(void); 
+

+ +

The D Way

+ + D is a strongly typed language, so there is no need to explicitly + say a function takes no arguments, just don't declare it has having + arguments. + +

+
+

+       void function() 
+       {   
+	   ... 
+       } 
+

+ +


+ +

Labelled break's and continue's.

+ +

The C Way

+ + Break's and continue's only apply to the innermost nested loop or + switch, so a multilevel break must use a goto: + +

+
+

+               for (i = 0; i < 10; i++) 
+               { 
+                   for (j = 0; j < 10; j++) 
+                   { 
+                       if (j == 3) 
+                           goto Louter; 
+                       if (j == 4) 
+                           goto L2; 
+                   } 
+                 L2: 
+                   ; 
+               } 
+           Louter: 
+               ; 
+

+ +

The D Way

+ + Break and continue statements can be followed by a label. The label + is the label for an enclosing loop or switch, and the break applies + to that loop. + +

+
+

+             Louter: 
+               for (i = 0; i < 10; i++) 
+               { 
+                   for (j = 0; j < 10; j++) 
+                   { 
+                       if (j == 3) 
+                           break Louter; 
+                       if (j == 4) 
+                           continue Louter; 
+                   } 
+               } 
+               // break Louter goes here 
+

+ +


+ +

Goto Statements

+ +

The C Way

+ + The much maligned goto statement is a staple for professional C coders. It's + necessary to make up for sometimes inadequate control flow statements. + +

The D Way

+ + Many C-way goto statements can be eliminated with the D feature of labelled + break and continue statements. But D is a practical language for practical + programmers who know when the rules need to be broken. So of course D supports + the goto! + +
+

Struct tag name space

+ +

The C Way

+ + It's annoying to have to put the struct keyword every time a type is specified, + so a common idiom is to use: + +

+
+

+               typedef struct ABC { ... } ABC; 
+

+ +

The D Way

+ + Struct tag names are not in a separate name space, they are in the same name + space as ordinary names. Hence: + +

+
+

+               struct ABC { ... }; 
+

+ +


+ +

Looking up strings

+ +

The C Way

+ + Given a string, compare the string against a list of possible + values and take action based on which one it is. A typical use + for this might be command line argument processing. + +

+
+

+               #include <string.h> 
+               void dostring(char *s) 
+               { 
+                   enum Strings { Hello, Goodbye, Maybe, Max }; 
+                   static char *table[] = { "hello", "goodbye", "maybe" }; 
+                   int i; 
+
+                   for (i = 0; i < Max; i++) 
+                   { 
+                       if (strcmp(s, table[i]) == 0) 
+                           break; 
+                   } 
+                   switch (i) 
+                   { 
+                       case Hello:        ... 
+                       case Goodbye:        ... 
+                       case Maybe:        ... 
+                       default:        ... 
+                   } 
+               } 
+

+ + The problem with this is trying to maintain 3 parallel data + structures, the enum, the table, and the switch cases. If there + are a lot of values, the connection between the 3 may not be so + obvious when doing maintenance, and so the situation is ripe for + bugs. + + Additionally, if the number of values becomes large, a binary or + hash lookup will yield a considerable performance increase over + a simple linear search. But coding these can be time consuming, + and they need to be debugged. It's typical that such just never + gets done. + +

The D Way

+ + D extends the concept of switch statements to be able to handle + strings as well as numbers. Then, the way to code the string + lookup becomes straightforward: + +

+
+

+               void dostring(char[] s) 
+               { 
+                   switch (s) 
+                   { 
+                       case "hello":        ... 
+                       case "goodbye":        ... 
+                       case "maybe":        ... 
+                       default:        ... 
+                   } 
+               } 
+

+ + Adding new cases becomes easy. The compiler can be relied on + to generate a fast lookup scheme for it, eliminating the bugs + and time required in hand-coding one. + +


+ +

Setting struct member alignment

+ +

The C Way

+ + It's done through a command line switch which affects the entire + program, and woe results if any modules or libraries didn't get + recompiled. To address this, #pragma's are used: + +

+
+

+           #pragma pack(1) 
+           struct ABC 
+           { 
+               ... 
+           }; 
+           #pragma pack() 
+

+ + But #pragmas are nonportable both in theory and in practice from + compiler to compiler. + +

The D Way

+ + Clearly, since much of the point to setting alignment is for + portability of data, a portable means of expressing it is necessary. + +

+
+

+           struct ABC 
+           { 
+               int z;               // z is aligned to the default 
+
+             align (1) int x;       // x is byte aligned 
+             align (4) 
+             { 
+               ...                  // declarations in {} are dword aligned 
+             } 
+             align (2):             // switch to word alignment from here on 
+
+               int y;               // y is word aligned 
+           } 
+

+ +


+ +

Anonymous Structs and Unions

+ +Sometimes, it's nice to control the layout of a struct with nested structs and unions. + +

The C Way

+ + C doesn't allow anonymous structs or unions, which means that dummy tag names + and dummy members are necessary: + +

+
+

+           struct Foo 
+           {   int i; 
+               union Bar 
+               { 
+                   struct Abc { int x; long y; } _abc; 
+                   char *p; 
+               } _bar; 
+           }; 
+
+           #define x _bar._abc.x 
+           #define y _bar._abc.y 
+           #define p _bar.p 
+
+           struct Foo f; 
+
+           f.i; 
+           f.x; 
+           f.y; 
+           f.p; 
+

+ + Not only is it clumsy, but using macros means a symbolic debugger won't understand + what is being done, and the macros have global scope instead of struct scope. + +

The D Way

+ + Anonymous structs and unions are used to control the layout in a + more natural manner: + +

+
+

+           struct Foo 
+           {   int i; 
+               union 
+               { 
+                   struct { int x; long y; } 
+                   char* p; 
+               } 
+           } 
+
+           Foo f; 
+
+           f.i; 
+           f.x; 
+           f.y; 
+           f.p; 
+

+ +


+ +

Declaring struct types and variables.

+ +

The C Way

+ + Is to do it in one statement ending with a semicolon: + +

+
+

+           struct Foo { int x; int y; } foo; 
+

+ + Or to separate the two: + +

+
+

+           struct Foo { int x; int y; };   // note terminating ; 
+           struct Foo foo; 
+

+ +

The D Way

+ + Struct definitions and declarations can't be done in the same statement: + +

+
+

+           struct Foo { int x; int y; }    // note there is no terminating ; 
+           Foo foo; 
+

+ + which means that the terminating ; can be dispensed with, eliminating the + confusing difference between struct {} and function & block {} in how semicolons + are used. + +


+ +

Getting the offset of a struct member.

+ +

The C Way

+ + Naturally, another macro is used: + +

+
+

+           #include <stddef> 
+           struct Foo { int x; int y; }; 
+
+           off = offsetof(Foo, y); 
+

+ +

The D Way

+ + An offset is just another property: + +

+
+

+           struct Foo { int x; int y; } 
+
+           off = Foo.y.offset; 
+

+ +


+ +

Union initializations.

+ +

The C Way

+ + Unions are initialized using the "first member" rule: + +

+
+

+           union U { int a; long b; }; 
+           union U x = { 5 };                // initialize member 'a' to 5 
+

+ + Adding union members or rearranging them can have disastrous consequences + for any initializers. + +

The D Way

+ + In D, which member is being initialized is mentioned explicitly: + +

+
+

+           union U { int a; long b; } 
+           U x = { a:5 } 
+

+ + avoiding the confusion and maintenance problems. + +


+ +

Struct initializations.

+ +

The C Way

+ + Members are initialized by their position within the {}'s: + +

+
+

+           struct S { int a; int b; }; 
+           struct S x = { 5, 3 }; 
+

+ + This isn't much of a problem with small structs, but when there + are numerous members, it becomes tedious to get the initializers + carefully lined up with the field declarations. Then, if members are + added or rearranged, all the initializations have to be found and + modified appropriately. This is a minefield for bugs. + +

The D Way

+ + Member initialization can be done explicitly: + +

+
+

+           struct S { int a; int b; } 
+           S x = { b:3, a:5 } 
+

+ + The meaning is clear, and there no longer is a positional dependence. + +


+ +

Array initializations.

+ +

The C Way

+ + C initializes array by positional dependence: +

+
+

+           int a[3] = { 3,2,2 }; 
+

+ Nested arrays may or may not have the { }: +

+
+

+           int b[3][2] = { 2,3, {6,5}, 3,4 }; 
+

+

The D Way

+ + D does it by positional dependence too, but an index can be used as well: + The following all produce the same result: +

+
+

+    int[3] a = [ 3, 2, 0 ]; 
+    int[3] a = [ 3, 2 ];            // unsupplied initializers are 0, just like in C 
+    int[3] a = [ 2:0, 0:3, 1:2 ]; 
+    int[3] a = [ 2:0, 0:3, 2 ];     // if not supplied, the index is the
+                                    // previous one plus one. 
+

+ This can be handy if the array will be indexed by an enum, and the order of + enums may be changed or added to: +

+
+

+    enum color { black, red, green }
+    int[3] c = [ black:3, green:2, red:5 ]; 
+

+ Nested array initializations must be explicit: +

+
+

+    int[2][3] b = [ [2,3], [6,5], [3,4] ]; 
+
+    int[2][3] b = [[2,6,3],[3,5,4]];            // error 
+

+ +


+ +

Escaped String Literals

+ +

The C Way

+ + C has problems with the DOS file system because a \ is an escape in a string. To specifiy file c:\root\file.c: +

+
+

+    char file[] = "c:\\root\\file.c"; 
+

+This gets even more unpleasant with regular expressions. +Consider the escape sequence to match a quoted string: +

+
+

+    /"[^\\]*(\\.[^\\]*)*"/
+

+

In C, this horror is expressed as: +

+
+

+    char quoteString[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\"";
+

+

The D Way

+ + Within strings, it is WYSIWYG (what you see is what you get). + Escapes are in separate strings. So: +

+
+

+    char[] file = 'c:\root\file.c'; 
+    char[] quoteString = \"  r"[^\\]*(\\.[^\\]*)*"  \";
+

+ The famous hello world string becomes: +

+
+

+    char[] hello = "hello world" \n; 
+

+ +


+ +

Ascii vs Wide Characters

+ +

Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs. + +

The C Way

+ + C uses the wchar_t and the L prefix on strings: +

+
+

+    #include <wchar.h> 
+    char foo_ascii[] = "hello"; 
+    wchar_t foo_wchar[] = L"hello"; 
+

+Things get worse if code is written to be both ascii and wchar compatible. +A macro is used to switch strings from ascii to wchar: +

+
+

+    #include <tchar.h> 
+    tchar string[] = TEXT("hello"); 
+

+

The D Way

+ +The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call: +

+
+

+    char[] foo_ascii = "hello";            // string is taken to be ascii 
+    wchar[] foo_wchar = "hello";       // string is taken to be wchar 
+

+ +


+ +

Arrays that parallel an enum

+ +

The C Way

+ + Consider: +

+
+

+       enum COLORS { red, blue, green, max }; 
+       char *cstring[max] = {"red", "blue", "green" }; 
+

+ This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added. + +

The D Way

+

+
+

+   enum COLORS { red, blue, green }
+
+    char[][COLORS.max + 1] cstring = 
+    [
+	COLORS.red   : "red",
+	COLORS.blue  : "blue", 
+	COLORS.green : "green",
+    ]; 
+

+ +Not perfect, but better. + +


+ +

Creating a new typedef'd type

+ +

The C Way

+ + Typedef's in C are weak, that is, they really do not introduce + a new type. The compiler doesn't distinguish between a typedef + and its underlying type. + +

+
+

+	typedef void *Handle;
+	void foo(void *);
+	void bar(Handle);
+
+	Handle h;
+	foo(h);			// coding bug not caught
+	bar(h);			// ok
+	

+ + The C solution is to create a dummy struct whose sole + purpose is to get type checking and overloading on the new type. + +

+
+

+	struct Handle__ { void *value; }
+	typedef struct Handle__ *Handle;
+	void foo(void *);
+	void bar(Handle);
+
+	Handle h;
+	foo(h);			// syntax error
+	bar(h);			// ok
+	

+ + Having a default value for the type involves defining a macro, + a naming convention, and then pedantically following that convention: + +

+
+

+	#define HANDLE_INIT ((Handle)-1)
+
+	Handle h = HANDLE_INIT;
+	h = func();
+	if (h != HANDLE_INIT)
+	    ...
+	

+ + For the struct solution, things get even more complex: + +

+
+

+	struct Handle__ HANDLE_INIT;
+
+	void init_handle()	// call this function upon startup
+	{
+	    HANDLE_INIT.value = (void *)-1;
+	}
+
+	Handle h = HANDLE_INIT;
+	h = func();
+	if (memcmp(&h,&HANDLE_INIT,sizeof(Handle)) != 0)
+	    ...
+	

+ + There are 4 names to remember: Handle, HANDLE_INIT, + struct Handle__, value. + +

The D Way

+ + No need for idiomatic constructions like the above. Just write: + +

+
+

+	typedef void* Handle;
+	void foo(void*);
+	void bar(Handle);
+
+	Handle h;
+	foo(h);
+	bar(h);
+	

+ + To handle a default value, add an initializer to the typedef, + and refer to it with the .init property: + +

+
+

+	typedef void* Handle = cast(void*)(-1);
+	Handle h;
+	h = func();
+	if (h != Handle.init)
+	    ...
+	

+ + There's only one name to remember: Handle. + +


+ +

Comparing structs

+ +

The C Way

+ + While C defines struct assignment in a simple, convenient manner: + +

+
+

+	struct A x, y;
+	...
+	x = y;
+	

+ + it does not for struct comparisons. Hence, to compare two struct + instances for equality: + +

+
+

+	#include <string.h>
+
+	struct A x, y;
+	...
+	if (memcmp(&x, &y, sizeof(struct A)) == 0)
+	    ...
+	

+ + Note the obtuseness of this, coupled with the lack of any kind + of help from the language with type checking. +

+ + There's a nasty bug lurking in the memcmp(). + The layout of a struct, due to alignment, can have 'holes' in it. + C does not guarantee those holes are assigned any values, and so + two different struct instances can have the same value for each member, + but compare different because the holes contain different garbage. + +

The D Way

+ + D does it the obvious, straightforward way: + +

+
+

+	A x, y;
+	...
+	if (x == y)
+	    ...
+	

+ + +


+

Comparing strings

+ +

The C Way

+ + The library function strcmp() is used: +

+
+

+	char string[] = "hello";
+
+	if (strcmp(string, "betty") == 0)	// do strings match?
+	    ...
+	

+ + C uses 0 terminated strings, so the C way has an inherent + inefficiency in constantly scanning for the terminating 0. + +

The D Way

+ + Why not use the == operator? + +

+
+

+	char[] string = "hello";
+
+	if (string == "betty")
+	    ...
+	

+ + D strings have the length stored separately from the string. + Thus, the implementation of string compares can be much faster + than in C (the difference being equivalent to the difference + in speed between the C memcmp() and strcmp()). +

+ + D supports comparison operators on strings, too: + +

+
+

+	char[] string = "hello";
+
+	if (string < "betty")
+	    ...
+	

+ + which is useful for sorting/searching. + +


+

Sorting arrays

+ +

The C Way

+ + Although many C programmers tend to reimplmement bubble sorts + over and over, the right way to sort in C is to use qsort(): + +

+
+

+	int compare(const void *p1, const void *p2)
+	{
+	    type *t1 = (type *)p1;
+	    type *t1 = (type *)p2;
+
+	    return *t1 - *t2;
+	}
+
+	type array[10];
+	...
+	qsort(array, sizeof(array)/sizeof(array[0]),
+		sizeof(array[0]), compare);
+	

+ + A compare() must be written for each type, and much careful + typo-prone code needs to be written to make it work. + + +

The D Way

+ + Sorting couldn't be easier: + +

+
+

+	type[] array;
+	...
+	array.sort;		// sort array in-place
+	

+ +


+

Volatile memory access

+ +

The C Way

+ + To access volatile memory, such as shared memory + or memory mapped I/O, a pointer to volatile is created: +

+
+

+	volatile int *p = address;
+
+	i = *p;
+	

+ +

The D Way

+ + D has volatile as a statement type, not as a type modifier: + +

+
+

+	int* p = address;
+
+	volatile { i = *p; }
+	

+ +


+

String literals

+ +

The C Way

+ + String literals in C cannot span multiple lines, so to have + a block of text it is necessary to use \ line splicing: + +

+
+

+	"This text spans\n
+	multiple\n
+	lines\n"
+	

+ + If there is a lot of text, this can wind up being tedious. + +

The D Way

+ + String literals can span multiple lines, as in: + +

+
+

+	"This text spans
+	multiple
+	lines
+	"
+	

+ + So blocks of text can just be cut and pasted into the D + source. + +


+

Data Structure Traversal

+ +

The C Way

+ + Consider a function to traverse a recursive data structure. + In this example, there's a simple symbol table of strings. + The data structure is an array of binary trees. + The code needs to do an exhaustive search of it to find + a particular string in it, and determine if it is a unique + instance. +

+ + To make this work, a helper function membersearchx + is needed to recursively + walk the trees. The helper function needs to read and write + some context outside of the trees, so a custom struct Paramblock + is created and a pointer to it is used to maximize efficiency. + +

+
+

+    struct Symbol
+    {	char *id;
+	struct Symbol *left;
+	struct Symbol *right;
+    };
+
+    struct Paramblock
+    {   char *id;
+	struct Symbol *sm;
+    };
+
+    static void membersearchx(struct Paramblock *p, struct Symbol *s)
+    {
+	while (s)
+	{
+	    if (strcmp(p->id,s->id) == 0)
+	    {
+		if (p->sm)
+		    error("ambiguous member %s\n",p->id);
+		p->sm = s;
+	    }
+
+	    if (s->left)
+		membersearchx(p,s->left);
+	    s = s->right;
+	}
+    }
+
+    struct Symbol *symbol_membersearch(Symbol *table[], int tablemax, char *id)
+    {
+	struct Paramblock pb;
+	int i;
+
+	pb.id = id;
+	pb.sm = NULL;
+	for (i = 0; i < tablemax; i++)
+	{
+	    membersearchx(pb, table[i]);
+	}
+	return pb.sm;
+    }
+    

+ +

The D Way

+ + This is the same algorithm in D, and it shrinks dramatically. + Since nested functions have access to the lexically enclosing + function's variables, there's no need for a Paramblock or + to deal with its bookkeeping details. The nested helper function + is contained wholly within the function that needs it, + improving locality and maintainability. +

+ + The performance of the two versions is indistinguishable. + +

+
+

+    class Symbol
+    {	char[] id;
+	Symbol left;
+	Symbol right;
+    }
+
+    Symbol symbol_membersearch(Symbol[] table, char[] id)
+    {   Symbol sm;
+
+	void membersearchx(Symbol s)
+	{
+	    while (s)
+	    {
+		if (id == s.id)
+		{
+		    if (sm)
+			error("ambiguous member %s\n", id);
+		    sm = s;
+		}
+
+		if (s.left)
+		    membersearchx(s.left);
+		s = s.right;
+	    }
+	}
+
+	for (int i = 0; i < table.length; i++)
+	{
+	    membersearchx(table[i]);
+	}
+	return sm;
+    }
+    

+ +


+

Unsigned Right Shift

+ +

The C Way

+ + The right shift operators >> and >>= are signed + shifts if the left operand is a signed integral type, and + are unsigned right shifts if the left operand is an unsigned + integral type. To produce an unsigned right shift on an int, + a cast is necessary: + +

+
+

+	int i, j;
+	...
+	j = (unsigned)i >> 3;
+	

+ + If i is an int, this works fine. But if i is + of a typedef'd type, + +

+
+

+	myint i, j;
+	...
+	j = (unsigned)i >> 3;
+	

+ + and myint happens to be a long int, then the cast to + unsigned + will silently throw away the most significant bits, corrupting + the answer. + +

The D Way

+ + D has the right shift operators >> and >>= which + behave as they do in C. But D also has explicitly unsigned + right shift operators >>> and >>>= which will + do an unsigned right shift regardless of the sign of the left + operand. Hence, + +

+
+

+	myint i, j;
+	...
+	j = i >>> 3;
+	

+ + avoids the unsafe cast and will work as expected with any integral + type. + +


+

Dynamic Closures

+ +

The C Way

+ + Consider a reusable container type. In order to be reusable, + it must support a way to apply arbitrary code to each element + of the container. This is done by creating an apply function + that accepts a function pointer to which is passed each + element of the container contents. +

+ + A generic context pointer is also needed, represented here by + void *p. The example here is of a trivial container + class that holds an array of int's, and a user of that container + that computes the maximum of those int's. + +

+
+

+	struct Collection
+	{
+	    int array[10];
+
+	    void apply(void *p, void (*fp)(void *, int))
+	    {
+		for (int i = 0; i < sizeof(array)/sizeof(array[0]); i++)
+		    fp(p, array[i]);
+	    }
+	};
+
+	void comp_max(void *p, int i)
+	{
+	    int *pmax = (int *)p;
+
+	    if (i > *pmax)
+		*pmax = i;
+	}
+
+	void func(Collection *c)
+	{
+	    int max = INT_MIN;
+
+	    c->apply(&max, comp_max);
+	}
+	

+ + The C way makes heavy use of pointers and casting. + The casting is tedious, error prone, and loses all type safety. + +

The D Way

+ + The D version makes use of delegates to transmit + context information for the apply function, + and nested functions both to capture context + information and to improve locality. + +

+
+
	class Collection
+	{
+	    int[10] array;
+
+	    void apply(void delegate(int) fp)
+	    {
+		for (int i = 0; i < array.length; i++)
+		    fp(array[i]);
+	    }
+	}
+
+	void func(Collection c)
+	{
+	    int max = int.min;
+
+	    void comp_max(int i)
+	    {
+		if (i > max)
+		    max = i;
+	    }
+
+	    c.apply(comp_max);
+	}

+ + Pointers are eliminated, as well as casting and generic + pointers. The D version is fully type safe. + An alternate method in D makes use of function literals: + +

+
+
	void func(Collection c)
+	{
+	    int max = int.min;
+
+	    c.apply(delegate(int i) { if (i > max) max = i; } );
+	}

+ + eliminating the need to create irrelevant function names. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/dbc.html dmd-0.124/dmd/html/d/dbc.html --- dmd-0.123/dmd/html/d/dbc.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/dbc.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,223 +1,269 @@ - - -Contract Programming - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update Aug 26, 2003 -


- -

Contract Programming

- - Contracts are a breakthrough technique to reduce the programming effort - for large projects. Contracts are the concept of preconditions, postconditions, - errors, and invariants. - Contracts can be done in C++ without modification to the language, - but the result is - clumsy and inconsistent. -

- - Building contract support into the language makes for: - -

    -
  1. a consistent look and feel for the contracts -
  2. tool support -
  3. it's possible the compiler can generate better code using information gathered - from the contracts -
  4. easier management and enforcement of contracts -
  5. handling of contract inheritance -
- -Contracts make D bug resistant - - The idea of a contract is simple - it's just an expression that must evaluate to true. - If it does not, the contract is broken, and by definition, the program has a bug in it. - Contracts form part of the specification for a program, moving it from the documentation - to the code itself. And as every programmer knows, documentation tends to be incomplete, - out of date, wrong, or non-existent. Moving the contracts into the code makes them - verifiable against the program. - -

Assert Contract

- - The most basic contract is the - assert. - An assert inserts a checkable expression into - the code, and that expression must evaluate to true: -
-	assert(expression);
-
- C programmers will find it familiar. Unlike C, however, an assert - in function bodies - works by throwing an AssertException, - which can be caught and handled. Catching the contract violation is useful - when the code must deal with errant uses by other code, when it must be - failure proof, and as a useful tool for debugging. - -

Pre and Post Contracts

- - The pre contracts specify the preconditions before a statement is executed. The most - typical use of this would be in validating the parameters to a function. The post - contracts validate the result of the statement. The most typical use of this - would be in validating the return value of a function and of any side effects it has. - The syntax is: - -
-	in
-	{
-	    ...contract preconditions...
-	}
-	out (result)
-	{
-	    ...contract postconditions...
-	}
-	body
-	{
-	    ...code...
-	}
-
- By definition, if a pre contract fails, then the body received bad parameters. - An InException is thrown. If a post contract fails, - then there is a bug in the body. An OutException is thrown. -

- Either the in or the out clause can be omitted. - If the out clause is for a function - body, the variable result is declared and assigned the return - value of the function. - For example, let's implement a square root function: -

-	long square_root(long x)
-	    in
-	    {
-		assert(x >= 0);
-	    }
-	    out (result)
-	    {
-		assert((result * result) == x);
-	    }
-	    body
-	    {
-		return math.sqrt(x);
-	    }
-
- The assert's in the in and out bodies are called contracts. - Any other D - statement or expression is allowed in the bodies, but it is important - to ensure that the - code has no side effects, and that the release version of the code - will not depend on any effects of the code. - For a release build of the code, the in and out code is not - inserted. -

- If the function returns a void, there is no result, and so there can be no - result declaration in the out clause. - In that case, use: -

-	void func()
-	   out
-	   {
-		...contracts...
-	   }
-	   body
-	   {
-		...
-	   }
-
- In an out statement, result is initialized and set to the - return value of the function. -

- The compiler can be adjusted to verify that every in and inout parameter is referenced - in the in { }, - and every out and inout parameter is referenced in the out { }. -

- The in-out statement can also be used inside a function, for example, it can be used - to check the results of a loop: -

-	in
-	{
-	    assert(j == 0);
-	}
-	out
-	{
-	    assert(j == 10);
-	}
-	body
-	{
-	    for (i = 0; i < 10; i++)
-		j++;
-	}
-
- This is not implemented at this time. - -

In, Out and Inheritance

- - If a function in a derived class overrides a function in its - super class, then only one of - the in contracts of the base functions must be satisified - Overriding - functions then becomes a process of loosening the in - contracts. -

- Conversely, all of the out contracts needs to be satisified, so - overriding functions becomes a processes of tightening the out - contracts. - - - -

Class Invariants

- - Class invariants are used to specify characteristics of a class that always - must be true (except while executing a member function). - They are described in Classes. - - -

References

-Contracts Reading List
-Adding Contracts to Java
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Contract Programming + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Contract Programming

+ + Contracts are a breakthrough technique to reduce the programming effort + for large projects. Contracts are the concept of preconditions, postconditions, + errors, and invariants. + Contracts can be done in C++ without modification to the language, + but the result is + clumsy and inconsistent. +

+ + Building contract support into the language makes for: + +

    +
  1. a consistent look and feel for the contracts +
  2. tool support +
  3. it's possible the compiler can generate better code using information gathered + from the contracts +
  4. easier management and enforcement of contracts +
  5. handling of contract inheritance +
+ +Contracts make D bug resistant + + The idea of a contract is simple - it's just an expression that must evaluate to true. + If it does not, the contract is broken, and by definition, the program has a bug in it. + Contracts form part of the specification for a program, moving it from the documentation + to the code itself. And as every programmer knows, documentation tends to be incomplete, + out of date, wrong, or non-existent. Moving the contracts into the code makes them + verifiable against the program. + +

Assert Contract

+ + The most basic contract is the + assert. + An assert inserts a checkable expression into + the code, and that expression must evaluate to true: +

+
+

+	assert(expression);
+

+ C programmers will find it familiar. Unlike C, however, an assert + in function bodies + works by throwing an AssertException, + which can be caught and handled. Catching the contract violation is useful + when the code must deal with errant uses by other code, when it must be + failure proof, and as a useful tool for debugging. + +

Pre and Post Contracts

+ + The pre contracts specify the preconditions before a statement is executed. The most + typical use of this would be in validating the parameters to a function. The post + contracts validate the result of the statement. The most typical use of this + would be in validating the return value of a function and of any side effects it has. + The syntax is: + +

+
+

+	in
+	{
+	    ...contract preconditions...
+	}
+	out (result)
+	{
+	    ...contract postconditions...
+	}
+	body
+	{
+	    ...code...
+	}
+

+ By definition, if a pre contract fails, then the body received bad parameters. + An InException is thrown. If a post contract fails, + then there is a bug in the body. An OutException is thrown. +

+ Either the in or the out clause can be omitted. + If the out clause is for a function + body, the variable result is declared and assigned the return + value of the function. + For example, let's implement a square root function: +

+
+

+	long square_root(long x)
+	    in
+	    {
+		assert(x >= 0);
+	    }
+	    out (result)
+	    {
+		assert((result * result) == x);
+	    }
+	    body
+	    {
+		return math.sqrt(x);
+	    }
+

+ The assert's in the in and out bodies are called contracts. + Any other D + statement or expression is allowed in the bodies, but it is important + to ensure that the + code has no side effects, and that the release version of the code + will not depend on any effects of the code. + For a release build of the code, the in and out code is not + inserted. +

+ If the function returns a void, there is no result, and so there can be no + result declaration in the out clause. + In that case, use: +

+
+

+	void func()
+	   out
+	   {
+		...contracts...
+	   }
+	   body
+	   {
+		...
+	   }
+

+ In an out statement, result is initialized and set to the + return value of the function. +

+ The compiler can be adjusted to verify that every in and inout parameter is referenced + in the in { }, + and every out and inout parameter is referenced in the out { }. +

+ The in-out statement can also be used inside a function, for example, it can be used + to check the results of a loop: +

+
+

+	in
+	{
+	    assert(j == 0);
+	}
+	out
+	{
+	    assert(j == 10);
+	}
+	body
+	{
+	    for (i = 0; i < 10; i++)
+		j++;
+	}
+

+ This is not implemented at this time. + +

In, Out and Inheritance

+ + If a function in a derived class overrides a function in its + super class, then only one of + the in contracts of the base functions must be satisified + Overriding + functions then becomes a process of loosening the in + contracts. +

+ Conversely, all of the out contracts needs to be satisified, so + overriding functions becomes a processes of tightening the out + contracts. + + + +

Class Invariants

+ + Class invariants are used to specify characteristics of a class that always + must be true (except while executing a member function). + They are described in Classes. + + +

References

+Contracts Reading List
+Adding Contracts to Java
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/dcompiler.html dmd-0.124/dmd/html/d/dcompiler.html --- dmd-0.123/dmd/html/d/dcompiler.html 2005-05-08 09:16:24.000000000 +0200 +++ dmd-0.124/dmd/html/d/dcompiler.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,540 +1,569 @@ - - - -Digital Mars - D Compiler - - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update May 7, 2008 -


- -

Compiler for D Programming Language

- - - -

Files Common to Win32 and Linux

- -
- -
\dmd\src\phobos\ -
D runtime library source - -
\dmd\src\dmd\ -
D compiler front end source under dual (GPL and Artistic) license - -
\dmd\html\d\ -
Documentation - -
\dmd\samples\d\ -
Sample D programs - -
- -
-

Win32 D Compiler

- -

Files

- -
- -
\dmd\bin\dmd.exe -
D compiler executable - -
\dmd\bin\shell.exe -
Simple command line shell - -
\dmd\bin\sc.ini -
Global compiler settings - -
\dmd\lib\phobos.lib -
D runtime library - -
- -

Requirements

- - - -

Installation

- - Open a console window (for Windows XP this is done by - clicking on [Start][Command Prompt]). - All the tools are command line tools, which means - they are run from a console window. - Switch to the root directory. - Unzip the files in the root directory. - dmd.zip will create - a \dmd directory with all the files in it. - dmc.zip will create - a \dm directory with all the files in it. -

- - A typical session might look like: - -

-	C:\Documents and Settings\Your Name>cd \
-	C:\>unzip dmd.zip
-	C:\>unzip dmc.zip
-	
- -

Example

- - Run: -
-	\dmd\bin\shell all.sh
-	
- in the \dmd\samples\d directory for several small examples. - -

Compiler Arguments and Switches

- -
-
dmd files... -switch... -

-

files... -
- - - - - - - - -
Extension - File Type -
none - D source files -
.d - D source files -
.obj - Object files to link in -
.exe - Name output executable file -
.def - module definition file -
.res - resource file -
-
-c
-
compile only, do not link -
-d
-
allow deprecated features -
-debug
-
compile in debug code -
-debug=level
-
compile in debug code <= level -
-debug=ident
-
compile in debug code identified by ident -
-g
-
add symbolic debug info -
-inline -
inline expand functions -
-Ipath -
where to look for imports. path is a ; separated - list of paths. Multiple -I's can be used, and the paths - are searched in the same order. -
-Llinkerflag -
pass linkerflag to the linker, for example, - /ma/li -
-O
-
optimize -
-odobjdir
-
write object files relative to directory objdir - instead of to the current directory -
-offilename
-
set output file name to filename in the output - directory -
-op
-
normally the path for .d source files is stripped - off when generating an object file name. -op will leave - it on. -
-profile
-
profile - the runtime performance - of the generated code -
-release
-
compile release version, which means not generating - code for contracts and asserts -
-unittest
-
compile in unittest code, also turns on asserts -
-v
-
verbose -
-version=level
-
compile in version code >= level -
-version=ident
-
compile in version code identified by ident -
-w
-
enable warnings -
- -

Linking

- - Linking is done directly by the dmd compiler after a successful - compile. To prevent dmd from running the linker, use the - -c switch. -

- - The programs must be linked with the D runtime library phobos.lib, - followed by the C runtime library snn.lib. - This is done automatically as long as the directories for the - libraries are on the LIB environment variable path. A typical - way to set LIB would be: -

-	set LIB=\dmd\lib;\dm\lib
-	
- -

Environment Variables

- - The D compiler dmd uses the following environment variables: - -
- -
DFLAGS -
The value of DFLAGS is treated as if it were appended to the - command line to dmd.exe. - -
LIB -
The linker uses LIB to search for library files. For D, it will - normally be set to: -
-	set LIB=\dmd\lib;\dm\lib
- -
LINKCMD -
dmd normally runs the linker by looking for link.exe - along the PATH. To use a specific linker instead, set the - LINKCMD environment variable to it. For example: -
-	set LINKCMD=\dm\bin\link
- -
PATH -
If the linker is not found in the same directory as dmd.exe - is in, the PATH is searched for it. - Note: other linkers named - link.exe will likely not work. - Make sure the Digital Mars link.exe - is found first in the PATH before other link.exe's, - or use LINKCMD to specifically identify which linker - to use. - -
- -

SC.INI Initialization File

- - dmd will look for the initialization file sc.ini in the same - directory dmd.exe resides in. If found, environment variable - settings in the file will override any existing settings. - This is handy to make dmd independent of programs with - conflicting use of environment variables. -

- - Environment variables follow the [Environment] section - heading, in name=value pairs. Comments are lines that start with ;. - For example: -

-	; sc.ini file for dmd
-	; Names enclosed by %% are searched for in the existing environment
-	; and inserted. The special name %@P% is replaced with the path
-	; to this file.
-	[Environment]
-	LIB="%@P%\..\lib";\dm\lib
-	DFLAGS="-I%@P%\..\src\phobos"
-	LINKCMD="%@P%\..\..\dm\bin"
-	
- -

Common Installation Problems

- - - -
-

Linux D Compiler

- -

Files

- -
- -
/dmd/bin/dmd -
D compiler executable - -
/dmd/bin/dumpobj -
Elf file dumper - -
/dmd/bin/obj2asm -
Elf file disassembler - -
/dmd/bin/dmd.conf -
Global compiler settings (copy to /etc/dmd.conf) - -
/dmd/lib/libphobos.a -
D runtime library (copy to /usr/lib/libphobos.a) - -
- -

Requirements

- - - -

Installation

- -
    - -
  1. Unzip the archive into your home directory. - It will create - a ~/dmd directory with all the files in it. - All the tools are command line tools, which means - they are run from a console window. - -
  2. Edit the file ~/dmd/bin/dmd.conf to put the path in to - where the phobos source files are. - -
  3. Copy dmd.conf to /etc: - -
    -	cp dmd/bin/dmd.conf /etc
    -	
    - -
  4. Give execute permission to the following files: - -
    -	chmod u+x dmd/bin/dmd dmd/bin/obj2asm dmd/bin/dumpobj
    -	
    - -
  5. Put dmd/bin on your PATH, - or copy the linux executables - to /usr/local/bin - -
  6. Copy the library to /usr/lib: - -
    -	cp dmd/lib/libphobos.a /usr/lib
    -	
    - -
- -

Compiler Arguments and Switches

- -
-
dmd files... -switch... -

-

files... -
- - - - - - - -
Extension - File Type -
none - D source files -
.d - D source files -
.o - Object files to link in -
.a - Library files to link in -
-
-c
-
compile only, do not link -
-d
-
allow deprecated features -
-debug
-
compile in debug code -
-debug=level
-
compile in debug code <= level -
-debug=ident
-
compile in debug code identified by ident -
-g
-
add symbolic debug info -
-inline -
inline expand functions -
-Ipath -
where to look for imports. path is a ; separated - list of paths. Multiple -I's can be used, and the paths - are searched in the same order. -
-Llinkerflag -
pass linkerflag to the linker, for example, - -M -
-O
-
optimize -
-odobjdir
-
write object files relative to directory objdir - instead of to the current directory -
-offilename
-
set output file name to filename in the output - directory -
-op
-
normally the path for .d source files is stripped - off when generating an object file name. -op will leave - it on. -
-profile
-
profile - the runtime performance - of the generated code -
-release
-
compile release version -
-unittest
-
compile in unittest code -
-v
-
verbose -
-version=level
-
compile in version code >= level -
-version=ident
-
compile in version code identified by ident -
-w
-
enable warnings -
- -

Linking

- - Linking is done directly by the dmd compiler after a successful - compile. To prevent dmd from running the linker, use the - -c switch. -

- - The actual linking is done by running gcc. - This ensures compatibility with modules compiled with gcc. - -

Environment Variables

- - The D compiler dmd uses the following environment variables: - -
- -
DFLAGS -
The value of DFLAGS is treated as if it were appended to the - command line to dmd. - -
- -

dmd.conf Initialization File

- - dmd will look for the initialization file dmd.conf - in the directory /etc. If found, environment variable - settings in the file will override any existing settings. - This is handy to make dmd independent of programs with - conflicting use of environment variables. -

- - Environment variables follow the [Environment] section - heading, in name=value pairs. Comments are lines that start with ;. - For example: -

-	; dmd.conf file for dmd
-	; Names enclosed by %% are searched for in the existing environment
-	; and inserted. The special name %@P% is replaced with the path
-	; to this file.
-	[Environment]
-	DFLAGS="-I%@P%\..\src\phobos"
-	
- -

Differences from Win32 version

- - - -

Linux Bugs

- - - -
-

General

- -

Bugs

- - These are some of the major bugs: - - - -

Questions?

- - We welcome all feedback - kudos, flames, bugs, suggestions, hints, - and most especially donated code! Join the fray in the - D forum. - - -

Feedback and Comments for this Page

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - DMD Compiler + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Compiler for D Programming Language

+ + + +

Files Common to Win32 and Linux

+ +
+ +
\dmd\src\phobos\ +
D runtime library source + +
\dmd\src\dmd\ +
D compiler front end source under dual (GPL and Artistic) license + +
\dmd\html\d\ +
Documentation + +
\dmd\samples\d\ +
Sample D programs + +
+ +
+

Win32 D Compiler

+ +

Files

+ +
+ +
\dmd\bin\dmd.exe +
D compiler executable + +
\dmd\bin\shell.exe +
Simple command line shell + +
\dmd\bin\sc.ini +
Global compiler settings + +
\dmd\lib\phobos.lib +
D runtime library + +
+ +

Requirements

+ + + +

Installation

+ + Open a console window (for Windows XP this is done by + clicking on [Start][Command Prompt]). + All the tools are command line tools, which means + they are run from a console window. + Switch to the root directory. + Unzip the files in the root directory. + dmd.zip will create + a \dmd directory with all the files in it. + dmc.zip will create + a \dm directory with all the files in it. +

+ + A typical session might look like: + +

+	C:\Documents and Settings\Your Name>cd 
+	C:\>unzip dmd.zip
+	C:\>unzip dmc.zip
+	
+ +

Example

+ + Run: +
+	\dmd\bin\shell all.sh
+	
+ in the \dmd\samples\d directory for several small examples. + +

Compiler Arguments and Switches

+ +
+
dmd files... -switch... +

+

files... +
+ + + + + + + + +
Extension + File Type +
none + D source files +
.d + D source files +
.obj + Object files to link in +
.exe + Name output executable file +
.def + module definition file +
.res + resource file +
+
-c
+
compile only, do not link +
-d
+
allow deprecated features +
-debug
+
compile in debug code +
-debug=level
+
compile in debug code <= level +
-debug=ident
+
compile in debug code identified by ident +
-g
+
add symbolic debug info +
-inline +
inline expand functions +
-Ipath +
where to look for imports. path is a ; separated + list of paths. Multiple -I's can be used, and the paths + are searched in the same order. +
-Llinkerflag +
pass linkerflag to the linker, for example, + /ma/li +
-O
+
optimize +
-odobjdir
+
write object files relative to directory objdir + instead of to the current directory +
-offilename
+
set output file name to filename in the output + directory +
-op
+
normally the path for .d source files is stripped + off when generating an object file name. -op will leave + it on. +
-profile
+
profile + the runtime performance + of the generated code +
-quiet
+
suppress non-essential compiler messages +
-release
+
compile release version, which means not generating + code for contracts and asserts +
-unittest
+
compile in unittest code, also turns on asserts +
-v
+
verbose +
-version=level
+
compile in version code >= level +
-version=ident
+
compile in version code identified by ident +
-w
+
enable warnings +
+ +

Linking

+ + Linking is done directly by the dmd compiler after a successful + compile. To prevent dmd from running the linker, use the + -c switch. +

+ + The programs must be linked with the D runtime library phobos.lib, + followed by the C runtime library snn.lib. + This is done automatically as long as the directories for the + libraries are on the LIB environment variable path. A typical + way to set LIB would be: +

+	set LIB=\dmd\lib;\dm\lib
+	
+ +

Environment Variables

+ + The D compiler dmd uses the following environment variables: + +
+ +
DFLAGS +
The value of DFLAGS is treated as if it were appended to the + command line to dmd.exe. + +
LIB +
The linker uses LIB to search for library files. For D, it will + normally be set to: +
+	set LIB=\dmd\lib;\dm\lib
+ +
LINKCMD +
dmd normally runs the linker by looking for link.exe + along the PATH. To use a specific linker instead, set the + LINKCMD environment variable to it. For example: +
+	set LINKCMD=\dm\bin\link
+ +
PATH +
If the linker is not found in the same directory as dmd.exe + is in, the PATH is searched for it. + Note: other linkers named + link.exe will likely not work. + Make sure the Digital Mars link.exe + is found first in the PATH before other link.exe's, + or use LINKCMD to specifically identify which linker + to use. + +
+ +

SC.INI Initialization File

+ + dmd will look for the initialization file sc.ini in the same + directory dmd.exe resides in. If found, environment variable + settings in the file will override any existing settings. + This is handy to make dmd independent of programs with + conflicting use of environment variables. +

+ + Environment variables follow the [Environment] section + heading, in name=value pairs. Comments are lines that start with ;. + For example: +

+	; sc.ini file for dmd
+	; Names enclosed by %% are searched for in the existing environment
+	; and inserted. The special name %@P% is replaced with the path
+	; to this file.
+	[Environment]
+	LIB="%@P%\..\lib";\dm\lib
+	DFLAGS="-I%@P%\..\src\phobos"
+	LINKCMD="%@P%\..\..\dm\bin"
+	
+ +

Common Installation Problems

+ + + +
+

Linux D Compiler

+ +

Files

+ +
+ +
/dmd/bin/dmd +
D compiler executable + +
/dmd/bin/dumpobj +
Elf file dumper + +
/dmd/bin/obj2asm +
Elf file disassembler + +
/dmd/bin/dmd.conf +
Global compiler settings (copy to /etc/dmd.conf) + +
/dmd/lib/libphobos.a +
D runtime library (copy to /usr/lib/libphobos.a) + +
+ +

Requirements

+ + + +

Installation

+ +
    + +
  1. Unzip the archive into your home directory. + It will create + a ~/dmd directory with all the files in it. + All the tools are command line tools, which means + they are run from a console window. + +
  2. Edit the file ~/dmd/bin/dmd.conf to put the path in to + where the phobos source files are. + +
  3. Copy dmd.conf to /etc: + +
    +	cp dmd/bin/dmd.conf /etc
    +	
    + +
  4. Give execute permission to the following files: + +
    +	chmod u+x dmd/bin/dmd dmd/bin/obj2asm dmd/bin/dumpobj
    +	
    + +
  5. Put dmd/bin on your PATH, + or copy the linux executables + to /usr/local/bin + +
  6. Copy the library to /usr/lib: + +
    +	cp dmd/lib/libphobos.a /usr/lib
    +	
    + +
+ +

Compiler Arguments and Switches

+ +
+
dmd files... -switch... +

+

files... +
+ + + + + + + +
Extension + File Type +
none + D source files +
.d + D source files +
.o + Object files to link in +
.a + Library files to link in +
+
-c
+
compile only, do not link +
-d
+
allow deprecated features +
-debug
+
compile in debug code +
-debug=level
+
compile in debug code <= level +
-debug=ident
+
compile in debug code identified by ident +
-g
+
add symbolic debug info +
-inline +
inline expand functions +
-Ipath +
where to look for imports. path is a ; separated + list of paths. Multiple -I's can be used, and the paths + are searched in the same order. +
-Llinkerflag +
pass linkerflag to the linker, for example, + -M +
-O
+
optimize +
-odobjdir
+
write object files relative to directory objdir + instead of to the current directory +
-offilename
+
set output file name to filename in the output + directory +
-op
+
normally the path for .d source files is stripped + off when generating an object file name. -op will leave + it on. +
-quiet
+
suppress non-essential compiler messages +
-profile
+
profile + the runtime performance + of the generated code +
-release
+
compile release version +
-unittest
+
compile in unittest code +
-v
+
verbose +
-version=level
+
compile in version code >= level +
-version=ident
+
compile in version code identified by ident +
-w
+
enable warnings +
+ +

Linking

+ + Linking is done directly by the dmd compiler after a successful + compile. To prevent dmd from running the linker, use the + -c switch. +

+ + The actual linking is done by running gcc. + This ensures compatibility with modules compiled with gcc. + +

Environment Variables

+ + The D compiler dmd uses the following environment variables: + +
+ +
DFLAGS +
The value of DFLAGS is treated as if it were appended to the + command line to dmd. + +
+ +

dmd.conf Initialization File

+ + dmd will look for the initialization file dmd.conf + in the directory /etc. If found, environment variable + settings in the file will override any existing settings. + This is handy to make dmd independent of programs with + conflicting use of environment variables. +

+ + Environment variables follow the [Environment] section + heading, in name=value pairs. Comments are lines that start with ;. + For example: +

+	; dmd.conf file for dmd
+	; Names enclosed by %% are searched for in the existing environment
+	; and inserted. The special name %@P% is replaced with the path
+	; to this file.
+	[Environment]
+	DFLAGS="-I%@P%\..\src\phobos"
+	
+ +

Differences from Win32 version

+ + + +

Linux Bugs

+ + + +
+

General

+ +

Bugs

+ + These are some of the major bugs: + + + +

Questions?

+ + We welcome all feedback - kudos, flames, bugs, suggestions, hints, + and most especially donated code! Join the fray in the + D forum. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/declaration.html dmd-0.124/dmd/html/d/declaration.html --- dmd-0.123/dmd/html/d/declaration.html 2005-05-08 01:48:34.000000000 +0200 +++ dmd-0.124/dmd/html/d/declaration.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,405 +1,467 @@ - - - - - -D Programming Language - Declarations - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last modified May 8, 2005. -


- -

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

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 © 1999-2005 by Digital Mars, All Rights Reserved

- - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Declarations + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

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

+ +

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 © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/dlinks.html dmd-0.124/dmd/html/d/dlinks.html --- dmd-0.123/dmd/html/d/dlinks.html 2005-04-15 13:13:18.000000000 +0200 +++ dmd-0.124/dmd/html/d/dlinks.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,346 +1,432 @@ - - - - - - - - - - - - - Digital Mars - The D Programming Language - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Apr 15, 2005 -


- -

D Links

- -These are links to other D resources! - - - - If you have any D code, documents, or web pages of interest to D programmers, - please - email - the links to Digital Mars! - - -
- -Cut & paste the following free images on your web pages of interest to - D programmers: -

- - D-Man - The D Programming Language - by Christopher Sauls - by Greg Peet - by Greg Peet - by Greg Peet - by Greg Peet - by Greg Peet - by Manfred Nowak - by Manfred Nowak - by David L. 'SpottedTiger' Davis - by David L. 'SpottedTiger' Davis -

- - Corto's - D button images: - D Language - - -

- If you'd like to contribute more images, please - email - them to Digital Mars! - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
-

- - Valid HTML 4.01! -

- Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +Digital Mars - The D Programming Language + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ +

D Links

+ + +

Wikis

+ + + +

Tools

+ + + +

Libraries

+ + + +

Games

+ + + +

Media

+ + + +

Comparisons and Benchmarks

+ + + +

Miscellaneous

+ + + +

Japanese Language

+ + + + +

Images

+ +Cut & paste the following free images on your web pages of interest to + D programmers: +

+ + by Manfred Nowak + D-Man + by Christopher Sauls +
+ by David L. 'SpottedTiger' Davis + by David L. 'SpottedTiger' Davis +
+ by Greg Peet + by Greg Peet + by Greg Peet + The D Programming Language + by Greg Peet + by Greg Peet + by Manfred Nowak +

+ + Corto's + D button images: + D Language + +

Submissions

+ + If you have any D code, documents, + images or web pages of interest to D + programmers, + please + email + the links to Digital Mars. +

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + + + + diff -uNr dmd-0.123/dmd/html/d/dll.html dmd-0.124/dmd/html/d/dll.html --- dmd-0.123/dmd/html/d/dll.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/dll.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,658 +1,691 @@ - - - - - -Digital Mars - Writing Win32 DLLs in D - - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Jan 26, 2005 -


- -

Writing Win32 DLLs in D

- - DLLs (Dynamic Link Libraries) are one of the foundations - of system programming for Windows. The D programming - language enables the creation of several different types of - DLLs. -

- - For background information on what DLLs are and how they work - Chapter 11 of Jeffrey Richter's book - - Advanced Windows is indispensible. -

- - This guide will show how to create DLLs of various types with D. - -

- -

DLLs with a C Interface

- - A DLL presenting a C interface can connect to any other code - in a language that supports calling C functions in a DLL. - - DLLs can be created in D in roughly the same way as in C. - A DllMain() - is required, looking like: - -
-	import std.c.windows.windows;
-	HINSTANCE g_hInst;
-
-	extern (C)
-	{
-		void gc_init();
-		void gc_term();
-		void _minit();
-		void _moduleCtor();
-		void _moduleUnitTests();
-	}
-
-	extern (Windows)
-	BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
-	{
-	    switch (ulReason)
-	    {
-		case DLL_PROCESS_ATTACH:
-		    gc_init();			// initialize GC
-		    _minit();			// initialize module list
-		    _moduleCtor();		// run module constructors
-		    _moduleUnitTests();		// run module unit tests
-		    break;
-
-		case DLL_PROCESS_DETACH:
-		    gc_term();			// shut down GC
-		    break;
-
-		case DLL_THREAD_ATTACH:
-		case DLL_THREAD_DETACH:
-		    // Multiple threads not supported yet
-		    return false;
-	    }
-	    g_hInst=hInstance;
-	    return true;
-	}
-	
- - Notes: - - - Link with a .def - (Module Definition File) - along the lines of: - -
-	LIBRARY         MYDLL
-	DESCRIPTION     'My DLL written in D'
-
-	EXETYPE		NT
-	CODE            PRELOAD DISCARDABLE
-	DATA            PRELOAD SINGLE
-
-	EXPORTS
-			DllGetClassObject       @2
-			DllCanUnloadNow         @3
-			DllRegisterServer       @4
-			DllUnregisterServer     @5
-	
- - The functions in the EXPORTS list are for illustration. - Replace them with the actual exported functions from MYDLL. - Alternatively, use implib. - Here's an example of a simple DLL with a function print() - which prints a string: - -

mydll2.d:

-
-module mydll;
-export void dllprint() { printf("hello dll world\n"); }
-	
- -

mydll.def:

-
-LIBRARY "mydll.dll"
-EXETYPE NT
-SUBSYSTEM WINDOWS
-CODE SHARED EXECUTE
-DATA WRITE
-	
- - Put the code above that contains DllMain() into a file dll.d. - Compile and link the dll with the following command: - -
-dmd -ofmydll.dll mydll2.d dll.d mydll.def
-implib/system mydll.lib mydll.dll
-	
- - which will create mydll.dll and mydll.lib. - Now for a program, test.d, which will use the dll: - -

test.d:

-
-import mydll;
-
-int main()
-{
-   mydll.dllprint();
-   return 0;
-}
-	
- - Create a clone of mydll2.d that doesn't have the function bodies: - -

mydll.d:

-
-export void dllprint();
-	
- - Compile and link with the command: -
-dmd test.d mydll.lib
-	
- - and run: -
-C:>test
-hello dll world
-C:>
-	
- - - -

Memory Allocation

- - D DLLs use garbage collected memory management. The question is what - happens when pointers to allocated data cross DLL boundaries? - If the DLL presents a C interface, one would assume the reason - for that is to connect with code written in other languages. - Those other languages will not know anything about D's memory - management. Thus, the C interface will have to shield the - DLL's callers from needing to know anything about it. -

- - There are many approaches to solving this problem: - -

- -

COM Programming

- - Many Windows API interfaces are in terms of COM (Common Object Model) - objects (also called OLE or ActiveX objects). A COM object is an object - who's first field is a pointer to a vtbl[], and the first 3 entries - in that vtbl[] are for QueryInterface(), AddRef(), and Release(). -

- - For understanding COM, Kraig Brockshmidt's - - Inside OLE - is an indispensible resource. -

- - COM objects are analogous to D interfaces. Any COM object can be - expressed as a D interface, and every D object with an interface X - can be exposed as a COM object X. - This means that D is compatible with COM objects implemented - in other languages. -

- - While not strictly necessary, the Phobos library provides an Object - useful as a super class for all D COM objects, called ComObject. - ComObject provides a default implementation for - QueryInterface(), AddRef(), and Release(). -

- - Windows COM objects use the Windows calling convention, which is not - the default for D, so COM functions need to have the attribute - extern (Windows). - - So, to write a COM object: - -

-	import std.c.windows.com;
-
-	class MyCOMobject : ComObject
-	{
-	    extern (Windows):
-		...
-	}
-	
- - The sample code includes an example COM client program and server DLL. - -

D code calling D code in DLLs

- - Having DLLs in D be able to talk to each other as if they - were statically linked together is, of course, very desirable - as code between applications can be shared, and different - DLLs can be independently developed. -

- - The underlying difficulty is what to do about garbage collection (gc). - Each EXE and DLL will have their own gc instance. While - these gc's can coexist without stepping on each other, - it's redundant and inefficient to have multiple gc's running. - The idea explored here is to pick one gc and have the DLLs - redirect their gc's to use that one. The one gc used here will be - the one in the EXE file, although it's also possible to make a - separate DLL just for the gc. -

- - The example will show both how to statically load a DLL, and - to dynamically load/unload it. -

- - Starting with the code for the DLL, mydll.d: -

-/*
- * MyDll demonstration of how to write D DLLs.
- */
-
-import std.c.stdio;
-import std.c.stdlib;
-import std.string;
-import std.c.windows.windows;
-import std.gc;
-
-HINSTANCE   g_hInst;
-
-extern (C)
-{
-	void _minit();
-	void _moduleCtor();
-	void _moduleDtor();
-	void _moduleUnitTests();
-}
-
-extern (Windows)
-    BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
-{
-    switch (ulReason)
-    {
-        case DLL_PROCESS_ATTACH:
-	    printf("DLL_PROCESS_ATTACH\n");
-	    break;
-
-        case DLL_PROCESS_DETACH:
-	    printf("DLL_PROCESS_DETACH\n");
-	    std.c.stdio._fcloseallp = null; // so stdio doesn't get closed
-	    break;
-
-        case DLL_THREAD_ATTACH:
-	    printf("DLL_THREAD_ATTACH\n");
-	    return false;
-
-        case DLL_THREAD_DETACH:
-	    printf("DLL_THREAD_DETACH\n");
-	    return false;
-    }
-    g_hInst = hInstance;
-    return true;
-}
-
-export void MyDLL_Initialize(void* gc)
-{
-    printf("MyDLL_Initialize()\n");
-    std.gc.setGCHandle(gc);
-    _minit();
-    _moduleCtor();
-//  _moduleUnitTests();
-}
-
-export void MyDLL_Terminate()
-{
-    printf("MyDLL_Terminate()\n");
-    _moduleDtor();			// run module destructors
-    std.gc.endGCHandle();
-}
-
-static this()
-{
-    printf("static this for mydll\n");
-}
-
-static ~this()
-{
-    printf("static ~this for mydll\n");
-}
-
-/* --------------------------------------------------------- */
-
-class MyClass
-{
-    char[] concat(char[] a, char[] b)
-    {
-	return a ~ " " ~ b;
-    }
-
-    void free(char[] s)
-    {
-	delete s;
-    }
-}
-
-export MyClass getMyClass()
-{
-    return new MyClass();
-}
-	
- -
-
DllMain -
This is the main entry point for any D DLL. It gets called - by the C startup code - (for DMC++, the source is \dm\src\win32\dllstart.c). - The printf's are placed there so one can trace how it gets - called. - Notice that the initialization and termination code seen in - the earlier DllMain sample code isn't there. - This is because the initialization will depend on who is loading - the DLL, and how it is loaded (statically or dynamically). - There isn't much to do here. - The only oddity is the setting of std.d.stdio._fcloseallp to - null. If this is not set to null, the C runtime will flush - and close all the standard I/O buffers (like stdout, - stderr, etc.) - shutting off further output. Setting it to null defers the - responsibility for that to the caller of the DLL. -

- -

MyDLL_Initialize -
So instead we'll have our own DLL initialization routine so - exactly when it is called can be controlled. - It must be called after the caller has initialized itself, - the Phobos runtime library, and the module constructors - (this would normally be by the time main() was entered). - This function takes one argument, a handle to the - caller's gc. We'll see how that handle is obtained later. - Instead of gc_init() being called to initialize - the DLL's gc, std.gc.setGCHandle() is called and passed the - handle to which gc to use. - This step informs the caller's gc - which data areas of the DLL to scan. - Afterwards follows the call to the _minit() to initialize the - module tables, and _moduleCtor() to run the module constructors. - _moduleUnitTests() is optional and runs the DLL's unit tests. - The function is exported as that is how a function is made - visible outside of a DLL. -

- -

MyDLL_Terminate -
Correspondingly, this function terminates the DLL, and is - called prior to unloading it. - It has two jobs; calling the DLL's module destructors via - _moduleDtor() and informing the runtime that - the DLL will no longer be using the caller's gc via - std.gc.endGCHandle(). - That last step is critical, as the DLL will be unmapped from - memory, and if the gc continues to scan its data areas it will - cause segment faults. -

- -

static this, static ~this -
These are examples of the module's static constructor - and destructor, - here with a print in each to verify that they are running - and when. -

- -

MyClass -
This is an example of a class that can be exported from - and used by the caller of a DLL. The concat member - function allocates some gc memory, and free frees gc - memory. -

- -

getMyClass -
An exported factory that allocates an instance of MyClass - and returns a reference to it. -

- -

- - To build the mydll.dll DLL: - -
    -
  1. dmd -c mydll -g -
    Compiles mydll.d into mydll.obj. - -g turns on debug info generation. -

    - -

  2. dmd mydll.obj \dmd\lib\gcstub.obj mydll.def -g -L/map -
    Links mydll.obj into a DLL named mydll.dll. - gcstub.obj is not required, but it prevents the bulk - of the gc code from being linked in, since it will not be used - anyway. It saves about 12Kb. - mydll.def is the - Module Definition File, - and has the contents: -
    -	LIBRARY         MYDLL
    -	DESCRIPTION     'MyDll demonstration DLL'
    -	EXETYPE		NT
    -	CODE            PRELOAD DISCARDABLE
    -	DATA            PRELOAD SINGLE
    - -g turns on debug info generation, and - -L/map generates a map file mydll.map. -

    - -

  3. implib /noi /system mydll.lib mydll.dll -
    Creates an - import library - mydll.lib suitable - for linking in with an application that will be statically - loading mydll.dll. -

    - -

- - Here's test.d, a sample application that makes use of - mydll.dll. There are two versions, one statically binds to - the DLL, and the other dynamically loads it. - -
-import std.stdio;
-import std.gc;
-
-import mydll;
-
-//version=DYNAMIC_LOAD;
-
-version (DYNAMIC_LOAD)
-{
-    import std.c.windows.windows;
-
-    alias void function(void*) MyDLL_Initialize_fp;
-    alias void function() MyDLL_Terminate_fp;
-    alias MyClass function() getMyClass_fp;
-
-    int main()
-    {	HMODULE h;
-	FARPROC fp;
-	MyDLL_Initialize_fp mydll_initialize;
-	MyDLL_Terminate_fp  mydll_terminate;
-
-	getMyClass_fp  getMyClass;
-	MyClass c;
-
-	printf("Start Dynamic Link...\n");
-
-	h = LoadLibraryA("mydll.dll");
-	if (h == null)
-	{   printf("error loading mydll.dll\n");
-	    return 1;
-	}
-
-	fp = GetProcAddress(h, "D5mydll16MyDLL_InitializeFPvZv");
-	if (fp == null)
-	{   printf("error loading symbol MyDLL_Initialize()\n");
-	    return 1;
-	}
-
-	mydll_initialize = cast(MyDLL_Initialize_fp) fp;
-	(*mydll_initialize)(std.gc.getGCHandle());
-
-	fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass");
-	if (fp == null)
-	{   printf("error loading symbol getMyClass()\n");
-	    return 1;
-	}
-
-	getMyClass = cast(getMyClass_fp) fp;
-	c = (*getMyClass)();
-	foo(c);
-
-	fp = GetProcAddress(h, "D5mydll15MyDLL_TerminateFZv");
-	if (fp == null)
-	{   printf("error loading symbol MyDLL_Terminate()\n");
-	    return 1;
-	}
-
-	mydll_terminate = cast(MyDLL_Terminate_fp) fp;
-	(*mydll_terminate)();
-
-	if (FreeLibrary(h) == FALSE)
-	{   printf("error freeing mydll.dll\n");
-	    return 1;
-	}
-
-	printf("End...\n");
-	return 0;
-    }
-}
-else
-{   // static link the DLL
-
-    int main()
-    {
-	printf("Start Static Link...\n");
-	MyDLL_Initialize(std.gc.getGCHandle());
-	foo(getMyClass());
-	MyDLL_Terminate();
-	printf("End...\n");
-	return 0;
-    }
-}
-
-void foo(MyClass c)
-{
-    char[] s;
-
-    s = c.concat("Hello", "world!");
-    writefln(s);
-    c.free(s);
-    delete c;
-}
-	
- - Let's start with the statically linked version, which is simpler. - It's compiled and linked with the command: -
dmd test mydll.lib -g
- Note how it is linked with mydll.lib, the import library - for mydll.dll. - The code is straightforward, it initializes mydll.lib with - a call to MyDLL_Initialize(), passing the handle - to test.exe's gc. - Then, we can use the DLL and call its functions just as if - it were part of test.exe. In foo(), gc memory - is allocated and freed both by test.exe and mydll.dll. - When we're done using the DLL, it is terminated with - MyDLL_Terminate(). -

- - Running it looks like this: -

-DLL_PROCESS_ATTACH
-Start Static Link...
-MyDLL_Initialize()
-static this for mydll
-Hello world!
-MyDLL_Terminate()
-static ~this for mydll
-End...
- - The dynamically linked version is a little harder to set up. - Compile and link it with the command: -
dmd test -version=DYNAMIC_LOAD -g
- The import library mydll.lib is not needed. - The DLL is loaded with a call to - LoadLibraryA(), - and each exported function has to be retrieved via - a call to - GetProcAddress(). - An easy way to get the decorated name to pass to GetProcAddress() - is to copy and paste it from the generated mydll.map file - under the Export heading. - Once this is done, we can use the member functions of the - DLL classes as if they were part of test.exe. - When done, release the DLL with - FreeLibrary(). -

- - Running it looks like this: -

-Start Dynamic Link...
-DLL_PROCESS_ATTACH
-MyDLL_Initialize()
-static this for mydll
-Hello world!
-MyDLL_Terminate()
-static ~this for mydll
-DLL_PROCESS_DETACH
-End...
- - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved - - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Writing Win32 DLLs + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

Writing Win32 DLLs in D

+ + DLLs (Dynamic Link Libraries) are one of the foundations + of system programming for Windows. The D programming + language enables the creation of several different types of + DLLs. +

+ + For background information on what DLLs are and how they work + Chapter 11 of Jeffrey Richter's book + + Advanced Windows is indispensible. +

+ + This guide will show how to create DLLs of various types with D. + +

+ +

DLLs with a C Interface

+ + A DLL presenting a C interface can connect to any other code + in a language that supports calling C functions in a DLL. + + DLLs can be created in D in roughly the same way as in C. + A DllMain() + is required, looking like: + +

+
+

+import std.c.windows.windows;
+HINSTANCE g_hInst;
+
+extern (C)
+{
+	void gc_init();
+	void gc_term();
+	void _minit();
+	void _moduleCtor();
+	void _moduleUnitTests();
+}
+
+extern (Windows)
+BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
+{
+    switch (ulReason)
+    {
+	case DLL_PROCESS_ATTACH:
+	    gc_init();			// initialize GC
+	    _minit();			// initialize module list
+	    _moduleCtor();		// run module constructors
+	    _moduleUnitTests();		// run module unit tests
+	    break;
+
+	case DLL_PROCESS_DETACH:
+	    gc_term();			// shut down GC
+	    break;
+
+	case DLL_THREAD_ATTACH:
+	case DLL_THREAD_DETACH:
+	    // Multiple threads not supported yet
+	    return false;
+    }
+    g_hInst=hInstance;
+    return true;
+}
+	

+ + Notes: +

+ + Link with a .def + (Module Definition File) + along the lines of: + +
+	LIBRARY         MYDLL
+	DESCRIPTION     'My DLL written in D'
+
+	EXETYPE		NT
+	CODE            PRELOAD DISCARDABLE
+	DATA            PRELOAD SINGLE
+
+	EXPORTS
+			DllGetClassObject       @2
+			DllCanUnloadNow         @3
+			DllRegisterServer       @4
+			DllUnregisterServer     @5
+	
+ + The functions in the EXPORTS list are for illustration. + Replace them with the actual exported functions from MYDLL. + Alternatively, use implib. + Here's an example of a simple DLL with a function print() + which prints a string: + +

mydll2.d:

+

+
+

+module mydll;
+export void dllprint() { printf("hello dll world\n"); }
+	

+ +

mydll.def:

+
+LIBRARY "mydll.dll"
+EXETYPE NT
+SUBSYSTEM WINDOWS
+CODE SHARED EXECUTE
+DATA WRITE
+	
+ + Put the code above that contains DllMain() into a file dll.d. + Compile and link the dll with the following command: + +
+dmd -ofmydll.dll mydll2.d dll.d mydll.def
+implib/system mydll.lib mydll.dll
+	
+ + which will create mydll.dll and mydll.lib. + Now for a program, test.d, which will use the dll: + +

test.d:

+

+
+

+import mydll;
+
+int main()
+{
+   mydll.dllprint();
+   return 0;
+}
+	

+ + Create a clone of mydll2.d that doesn't have the function bodies: + +

mydll.d:

+

+
+

+export void dllprint();
+	

+ + Compile and link with the command: +

+dmd test.d mydll.lib
+	
+ + and run: +
+C:>test
+hello dll world
+C:>
+	
+ + + +

Memory Allocation

+ + D DLLs use garbage collected memory management. The question is what + happens when pointers to allocated data cross DLL boundaries? + If the DLL presents a C interface, one would assume the reason + for that is to connect with code written in other languages. + Those other languages will not know anything about D's memory + management. Thus, the C interface will have to shield the + DLL's callers from needing to know anything about it. +

+ + There are many approaches to solving this problem: + +

+ +

COM Programming

+ + Many Windows API interfaces are in terms of COM (Common Object Model) + objects (also called OLE or ActiveX objects). A COM object is an object + who's first field is a pointer to a vtbl[], and the first 3 entries + in that vtbl[] are for QueryInterface(), AddRef(), and Release(). +

+ + For understanding COM, Kraig Brockshmidt's + + Inside OLE + is an indispensible resource. +

+ + COM objects are analogous to D interfaces. Any COM object can be + expressed as a D interface, and every D object with an interface X + can be exposed as a COM object X. + This means that D is compatible with COM objects implemented + in other languages. +

+ + While not strictly necessary, the Phobos library provides an Object + useful as a super class for all D COM objects, called ComObject. + ComObject provides a default implementation for + QueryInterface(), AddRef(), and Release(). +

+ + Windows COM objects use the Windows calling convention, which is not + the default for D, so COM functions need to have the attribute + extern (Windows). + + So, to write a COM object: + +

+
+

+import std.c.windows.com;
+
+class MyCOMobject : ComObject
+{
+    extern (Windows):
+	...
+}
+	

+ + The sample code includes an example COM client program and server DLL. + +

D code calling D code in DLLs

+ + Having DLLs in D be able to talk to each other as if they + were statically linked together is, of course, very desirable + as code between applications can be shared, and different + DLLs can be independently developed. +

+ + The underlying difficulty is what to do about garbage collection (gc). + Each EXE and DLL will have their own gc instance. While + these gc's can coexist without stepping on each other, + it's redundant and inefficient to have multiple gc's running. + The idea explored here is to pick one gc and have the DLLs + redirect their gc's to use that one. The one gc used here will be + the one in the EXE file, although it's also possible to make a + separate DLL just for the gc. +

+ + The example will show both how to statically load a DLL, and + to dynamically load/unload it. +

+ + Starting with the code for the DLL, mydll.d: +

+
+

+/*
+ * MyDll demonstration of how to write D DLLs.
+ */
+
+import std.c.stdio;
+import std.c.stdlib;
+import std.string;
+import std.c.windows.windows;
+import std.gc;
+
+HINSTANCE   g_hInst;
+
+extern (C)
+{
+	void _minit();
+	void _moduleCtor();
+	void _moduleDtor();
+	void _moduleUnitTests();
+}
+
+extern (Windows)
+    BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
+{
+    switch (ulReason)
+    {
+        case DLL_PROCESS_ATTACH:
+	    printf("DLL_PROCESS_ATTACH\n");
+	    break;
+
+        case DLL_PROCESS_DETACH:
+	    printf("DLL_PROCESS_DETACH\n");
+	    std.c.stdio._fcloseallp = null; // so stdio doesn't get closed
+	    break;
+
+        case DLL_THREAD_ATTACH:
+	    printf("DLL_THREAD_ATTACH\n");
+	    return false;
+
+        case DLL_THREAD_DETACH:
+	    printf("DLL_THREAD_DETACH\n");
+	    return false;
+    }
+    g_hInst = hInstance;
+    return true;
+}
+
+export void MyDLL_Initialize(void* gc)
+{
+    printf("MyDLL_Initialize()\n");
+    std.gc.setGCHandle(gc);
+    _minit();
+    _moduleCtor();
+//  _moduleUnitTests();
+}
+
+export void MyDLL_Terminate()
+{
+    printf("MyDLL_Terminate()\n");
+    _moduleDtor();			// run module destructors
+    std.gc.endGCHandle();
+}
+
+static this()
+{
+    printf("static this for mydll\n");
+}
+
+static ~this()
+{
+    printf("static ~this for mydll\n");
+}
+
+/* --------------------------------------------------------- */
+
+class MyClass
+{
+    char[] concat(char[] a, char[] b)
+    {
+	return a ~ " " ~ b;
+    }
+
+    void free(char[] s)
+    {
+	delete s;
+    }
+}
+
+export MyClass getMyClass()
+{
+    return new MyClass();
+}
+	

+ +

+
DllMain +
This is the main entry point for any D DLL. It gets called + by the C startup code + (for DMC++, the source is \dm\src\win32\dllstart.c). + The printf's are placed there so one can trace how it gets + called. + Notice that the initialization and termination code seen in + the earlier DllMain sample code isn't there. + This is because the initialization will depend on who is loading + the DLL, and how it is loaded (statically or dynamically). + There isn't much to do here. + The only oddity is the setting of std.d.stdio._fcloseallp to + null. If this is not set to null, the C runtime will flush + and close all the standard I/O buffers (like stdout, + stderr, etc.) + shutting off further output. Setting it to null defers the + responsibility for that to the caller of the DLL. +

+ +

MyDLL_Initialize +
So instead we'll have our own DLL initialization routine so + exactly when it is called can be controlled. + It must be called after the caller has initialized itself, + the Phobos runtime library, and the module constructors + (this would normally be by the time main() was entered). + This function takes one argument, a handle to the + caller's gc. We'll see how that handle is obtained later. + Instead of gc_init() being called to initialize + the DLL's gc, std.gc.setGCHandle() is called and passed the + handle to which gc to use. + This step informs the caller's gc + which data areas of the DLL to scan. + Afterwards follows the call to the _minit() to initialize the + module tables, and _moduleCtor() to run the module constructors. + _moduleUnitTests() is optional and runs the DLL's unit tests. + The function is exported as that is how a function is made + visible outside of a DLL. +

+ +

MyDLL_Terminate +
Correspondingly, this function terminates the DLL, and is + called prior to unloading it. + It has two jobs; calling the DLL's module destructors via + _moduleDtor() and informing the runtime that + the DLL will no longer be using the caller's gc via + std.gc.endGCHandle(). + That last step is critical, as the DLL will be unmapped from + memory, and if the gc continues to scan its data areas it will + cause segment faults. +

+ +

static this, static ~this +
These are examples of the module's static constructor + and destructor, + here with a print in each to verify that they are running + and when. +

+ +

MyClass +
This is an example of a class that can be exported from + and used by the caller of a DLL. The concat member + function allocates some gc memory, and free frees gc + memory. +

+ +

getMyClass +
An exported factory that allocates an instance of MyClass + and returns a reference to it. +

+ +

+ + To build the mydll.dll DLL: + +
    +
  1. dmd -c mydll -g +
    Compiles mydll.d into mydll.obj. + -g turns on debug info generation. +

    + +

  2. dmd mydll.obj \dmd\lib\gcstub.obj mydll.def -g -L/map +
    Links mydll.obj into a DLL named mydll.dll. + gcstub.obj is not required, but it prevents the bulk + of the gc code from being linked in, since it will not be used + anyway. It saves about 12Kb. + mydll.def is the + Module Definition File, + and has the contents: +
    +	LIBRARY         MYDLL
    +	DESCRIPTION     'MyDll demonstration DLL'
    +	EXETYPE		NT
    +	CODE            PRELOAD DISCARDABLE
    +	DATA            PRELOAD SINGLE
    + -g turns on debug info generation, and + -L/map generates a map file mydll.map. +

    + +

  3. implib /noi /system mydll.lib mydll.dll +
    Creates an + import library + mydll.lib suitable + for linking in with an application that will be statically + loading mydll.dll. +

    + +

+ + Here's test.d, a sample application that makes use of + mydll.dll. There are two versions, one statically binds to + the DLL, and the other dynamically loads it. + +

+
+

+import std.stdio;
+import std.gc;
+
+import mydll;
+
+//version=DYNAMIC_LOAD;
+
+version (DYNAMIC_LOAD)
+{
+    import std.c.windows.windows;
+
+    alias void function(void*) MyDLL_Initialize_fp;
+    alias void function() MyDLL_Terminate_fp;
+    alias MyClass function() getMyClass_fp;
+
+    int main()
+    {	HMODULE h;
+	FARPROC fp;
+	MyDLL_Initialize_fp mydll_initialize;
+	MyDLL_Terminate_fp  mydll_terminate;
+
+	getMyClass_fp  getMyClass;
+	MyClass c;
+
+	printf("Start Dynamic Link...\n");
+
+	h = LoadLibraryA("mydll.dll");
+	if (h == null)
+	{   printf("error loading mydll.dll\n");
+	    return 1;
+	}
+
+	fp = GetProcAddress(h, "D5mydll16MyDLL_InitializeFPvZv");
+	if (fp == null)
+	{   printf("error loading symbol MyDLL_Initialize()\n");
+	    return 1;
+	}
+
+	mydll_initialize = cast(MyDLL_Initialize_fp) fp;
+	(*mydll_initialize)(std.gc.getGCHandle());
+
+	fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass");
+	if (fp == null)
+	{   printf("error loading symbol getMyClass()\n");
+	    return 1;
+	}
+
+	getMyClass = cast(getMyClass_fp) fp;
+	c = (*getMyClass)();
+	foo(c);
+
+	fp = GetProcAddress(h, "D5mydll15MyDLL_TerminateFZv");
+	if (fp == null)
+	{   printf("error loading symbol MyDLL_Terminate()\n");
+	    return 1;
+	}
+
+	mydll_terminate = cast(MyDLL_Terminate_fp) fp;
+	(*mydll_terminate)();
+
+	if (FreeLibrary(h) == FALSE)
+	{   printf("error freeing mydll.dll\n");
+	    return 1;
+	}
+
+	printf("End...\n");
+	return 0;
+    }
+}
+else
+{   // static link the DLL
+
+    int main()
+    {
+	printf("Start Static Link...\n");
+	MyDLL_Initialize(std.gc.getGCHandle());
+	foo(getMyClass());
+	MyDLL_Terminate();
+	printf("End...\n");
+	return 0;
+    }
+}
+
+void foo(MyClass c)
+{
+    char[] s;
+
+    s = c.concat("Hello", "world!");
+    writefln(s);
+    c.free(s);
+    delete c;
+}
+	

+ + Let's start with the statically linked version, which is simpler. + It's compiled and linked with the command: +

dmd test mydll.lib -g
+ Note how it is linked with mydll.lib, the import library + for mydll.dll. + The code is straightforward, it initializes mydll.lib with + a call to MyDLL_Initialize(), passing the handle + to test.exe's gc. + Then, we can use the DLL and call its functions just as if + it were part of test.exe. In foo(), gc memory + is allocated and freed both by test.exe and mydll.dll. + When we're done using the DLL, it is terminated with + MyDLL_Terminate(). +

+ + Running it looks like this: +

+DLL_PROCESS_ATTACH
+Start Static Link...
+MyDLL_Initialize()
+static this for mydll
+Hello world!
+MyDLL_Terminate()
+static ~this for mydll
+End...
+ + The dynamically linked version is a little harder to set up. + Compile and link it with the command: +
dmd test -version=DYNAMIC_LOAD -g
+ The import library mydll.lib is not needed. + The DLL is loaded with a call to + LoadLibraryA(), + and each exported function has to be retrieved via + a call to + GetProcAddress(). + An easy way to get the decorated name to pass to GetProcAddress() + is to copy and paste it from the generated mydll.map file + under the Export heading. + Once this is done, we can use the member functions of the + DLL classes as if they were part of test.exe. + When done, release the DLL with + FreeLibrary(). +

+ + Running it looks like this: +

+Start Dynamic Link...
+DLL_PROCESS_ATTACH
+MyDLL_Initialize()
+static this for mydll
+Hello world!
+MyDLL_Terminate()
+static ~this for mydll
+DLL_PROCESS_DETACH
+End...
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/dstyle.html dmd-0.124/dmd/html/d/dstyle.html --- dmd-0.123/dmd/html/d/dstyle.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/dstyle.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,183 +1,227 @@ - - - - - -Digital Mars - The D Programming Language - The D Style - - - -www.digitalmars.com -[Home] -[Search] -[D] -

Last update May 25, 2002 -


- -

The D Style

- - The D Style is a set of style conventions for writing - D programs. The D Style is not enforced by the compiler, it is - purely cosmetic and a matter of choice. Adhering to the D Style, - however, will make it easier for others to work with your D - code and easier for you to work with others' D code. - The D Style can form the starting point for a D project - style guide customized for your project team. - -

White Space

- - - -

Comments

- - - -

Naming Conventions

- -
-
General -
Names formed by joining multiple works should have each word - other than the first capitalized. - -
-	int myFunc();
-	
- -
Module
-
Module names are all lower case. This avoids problems dealing - with case insensitive file systems. -

- -

C Modules
-
Modules that are interfaces to C functions go into the "c" - package, for example: -
-	import std.c.stdio;
-	
- Module names should be all lower case. -

- -

Class, Struct, Union, Enum names -
are capitalized. - -
-	class Foo;
-	class FooAndBar;
-	
- -
Function names -
Function names are not capitalized. - -
-	int done();
-	int doneProcessing();
-	
- -
Const names -
Are in all caps. - -
Enum member names -
Are in all caps. - -
- -

Meaningless Type Aliases

- - Things like: - -
-	alias void VOID;
-	alias int INT;
-	alias int* pint;
-	
- - should be avoided. - -

Declaration Style

- - Since in D the declarations are left-associative, left justify them: - -
-	int[] x, y;	// makes it clear that x and y are the same type
-	int** p, q;	// makes it clear that p and q are the same type
-	
- - to emphasize their relationship. Do not use the C style: - -
-	int []x, y;	// confusing since y is also an int[]
-	int **p, q;	// confusing since q is also an int**
-	
- -

Operator Overloading

- - Operator overloading is a powerful tool to extend the basic - types supported by the language. But being powerful, it has - great potential for creating obfuscated code. In particular, - the existing D operators have conventional meanings, such - as '+' means 'add' and '<<' means 'shift left'. - Overloading operator '+' with a meaning different from 'add' - is arbitrarily confusing and should be avoided. - -

Hungarian Notation

- - Just say no. - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright (c) 1999-2004 by Digital Mars, All Rights Reserved - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - The D Style + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

The D Style

+ + The D Style is a set of style conventions for writing + D programs. The D Style is not enforced by the compiler, it is + purely cosmetic and a matter of choice. Adhering to the D Style, + however, will make it easier for others to work with your D + code and easier for you to work with others' D code. + The D Style can form the starting point for a D project + style guide customized for your project team. + +

White Space

+ + + +

Comments

+ + + +

Naming Conventions

+ +
+
General +
Names formed by joining multiple works should have each word + other than the first capitalized. + +

+
+

+	int myFunc();
+	

+ +

Module
+
Module names are all lower case. This avoids problems dealing + with case insensitive file systems. +

+ +

C Modules
+
Modules that are interfaces to C functions go into the "c" + package, for example: +

+
+

+	import std.c.stdio;
+	

+ Module names should be all lower case. +

+ +

Class, Struct, Union, Enum names +
are capitalized. + +

+
+

+	class Foo;
+	class FooAndBar;
+	

+ +

Function names +
Function names are not capitalized. + +

+
+

+	int done();
+	int doneProcessing();
+	

+ +

Const names +
Are in all caps. + +
Enum member names +
Are in all caps. + +
+ +

Meaningless Type Aliases

+ + Things like: + +

+
+

+	alias void VOID;
+	alias int INT;
+	alias int* pint;
+	

+ + should be avoided. + +

Declaration Style

+ + Since in D the declarations are left-associative, left justify them: + +

+
+

+	int[] x, y;	// makes it clear that x and y are the same type
+	int** p, q;	// makes it clear that p and q are the same type
+	

+ + to emphasize their relationship. Do not use the C style: + +

+
+

+	int []x, y;	// confusing since y is also an int[]
+	int **p, q;	// confusing since q is also an int**
+	

+ +

Operator Overloading

+ + Operator overloading is a powerful tool to extend the basic + types supported by the language. But being powerful, it has + great potential for creating obfuscated code. In particular, + the existing D operators have conventional meanings, such + as '+' means 'add' and '<<' means 'shift left'. + Overloading operator '+' with a meaning different from 'add' + is arbitrarily confusing and should be avoided. + +

Hungarian Notation

+ + Just say no. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/entity.html dmd-0.124/dmd/html/d/entity.html --- dmd-0.123/dmd/html/d/entity.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/entity.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,305 +1,335 @@ - - -D Programming Language - Named Character Entities - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Mar 14, 2005 -


- -

Named Character Entities

- - These are the character entity names supported by D. -

- - Note: Not all will display properly in the Symbol - column in all browsers. -

- - - -

- -
Name Value Symbol - -
quot 34 " -
amp 38 & -
lt 60 < -
gt 62 > - -
OElig 338 Œ -
oelig 339 œ -
Scaron 352 Š -
scaron 353 š -
Yuml 376 Ÿ -
circ 710 ˆ -
tilde 732 ˜ -
ensp 8194   -
emsp 8195   -
thinsp 8201   -
zwnj 8204 ‌ -
zwj 8205 ‍ -
lrm 8206 ‎ -
rlm 8207 ‏ -
ndash 8211 – -
mdash 8212 — -
lsquo 8216 ‘ -
rsquo 8217 ’ -
sbquo 8218 ‚ -
ldquo 8220 “ -
rdquo 8221 ” -
bdquo 8222 „ -
dagger 8224 † -
Dagger 8225 ‡ -
permil 8240 ‰ -
lsaquo 8249 ‹ -
rsaquo 8250 › -
euro 8364 € - - - -
nbsp 160   -
iexcl 161 ¡ -
cent 162 ¢ -
pound 163 £ -
curren 164 ¤ -
yen 165 ¥ -
brvbar 166 ¦ -
sect 167 § -
uml 168 ¨ -
copy 169 © -
ordf 170 ª -
laquo 171 « -
not 172 ¬ -
shy 173 ­ -
reg 174 ® -
macr 175 ¯ -
deg 176 ° -
plusmn 177 ± -
sup2 178 ² -
sup3 179 ³ -
acute 180 ´ -
micro 181 µ -
para 182 ¶ -
middot 183 · -
cedil 184 ¸ -
sup1 185 ¹ -
ordm 186 º -
raquo 187 » -
frac14 188 ¼ -
frac12 189 ½ -
frac34 190 ¾ -
iquest 191 ¿ -
Agrave 192 À -
Aacute 193 Á -
Acirc 194 Â -
Atilde 195 Ã -
Auml 196 Ä -
Aring 197 Å -
AElig 198 Æ -
Ccedil 199 Ç -
Egrave 200 È -
Eacute 201 É -
Ecirc 202 Ê -
Euml 203 Ë -
Igrave 204 Ì -
Iacute 205 Í -
Icirc 206 Î -
Iuml 207 Ï -
ETH 208 Ð -
Ntilde 209 Ñ -
Ograve 210 Ò -
Oacute 211 Ó -
Ocirc 212 Ô -
Otilde 213 Õ -
Ouml 214 Ö -
times 215 × -
Oslash 216 Ø -
Ugrave 217 Ù -
Uacute 218 Ú -
Ucirc 219 Û -
Uuml 220 Ü -
Yacute 221 Ý -
THORN 222 Þ -
szlig 223 ß -
agrave 224 à -
aacute 225 á -
acirc 226 â -
atilde 227 ã -
auml 228 ä -
aring 229 å -
aelig 230 æ -
ccedil 231 ç -
egrave 232 è -
eacute 233 é -
ecirc 234 ê -
euml 235 ë -
igrave 236 ì -
iacute 237 í -
icirc 238 î -
iuml 239 ï -
eth 240 ð -
ntilde 241 ñ -
ograve 242 ò -
oacute 243 ó -
ocirc 244 ô -
otilde 245 õ -
ouml 246 ö -
divide 247 ÷ -
oslash 248 ø -
ugrave 249 ù -
uacute 250 ú -
ucirc 251 û -
uuml 252 ü -
yacute 253 ý -
thorn 254 þ -
yuml 255 ÿ - - - -
fnof 402 ƒ -
Alpha 913 Α -
Beta 914 Β -
Gamma 915 Γ -
Delta 916 Δ -
Epsilon 917 Ε -
Zeta 918 Ζ -
Eta 919 Η -
Theta 920 Θ -
Iota 921 Ι -
Kappa 922 Κ -
Lambda 923 Λ -
Mu 924 Μ -
Nu 925 Ν -
Xi 926 Ξ -
Omicron 927 Ο -
Pi 928 Π -
Rho 929 Ρ -
Sigma 931 Σ -
Tau 932 Τ -
Upsilon 933 Υ -
Phi 934 Φ -
Chi 935 Χ -
Psi 936 Ψ -
Omega 937 Ω -
alpha 945 α -
beta 946 β -
gamma 947 γ -
delta 948 δ -
epsilon 949 ε -
zeta 950 ζ -
eta 951 η -
theta 952 θ -
iota 953 ι -
kappa 954 κ -
lambda 955 λ -
mu 956 μ -
nu 957 ν -
xi 958 ξ -
omicron 959 ο -
pi 960 π -
rho 961 ρ -
sigmaf 962 ς -
sigma 963 σ -
tau 964 τ -
upsilon 965 υ -
phi 966 φ -
chi 967 χ -
psi 968 ψ -
omega 969 ω -
thetasym 977 ϑ -
upsih 978 ϒ -
piv 982 ϖ -
bull 8226 • -
hellip 8230 … -
prime 8242 ′ -
Prime 8243 ″ -
oline 8254 ‾ -
frasl 8260 ⁄ -
weierp 8472 ℘ -
image 8465 ℑ -
real 8476 ℜ -
trade 8482 ™ -
alefsym 8501 ℵ -
larr 8592 ← -
uarr 8593 ↑ -
rarr 8594 → -
darr 8595 ↓ -
harr 8596 ↔ -
crarr 8629 ↵ -
lArr 8656 ⇐ -
uArr 8657 ⇑ -
rArr 8658 ⇒ -
dArr 8659 ⇓ -
hArr 8660 ⇔ -
forall 8704 ∀ -
part 8706 ∂ -
exist 8707 ∃ -
empty 8709 ∅ -
nabla 8711 ∇ -
isin 8712 ∈ -
notin 8713 ∉ -
ni 8715 ∋ -
prod 8719 ∏ -
sum 8721 ∑ -
minus 8722 − -
lowast 8727 ∗ -
radic 8730 √ -
prop 8733 ∝ -
infin 8734 ∞ -
ang 8736 ∠ -
and 8743 ∧ -
or 8744 ∨ -
cap 8745 ∩ -
cup 8746 ∪ -
int 8747 ∫ -
there4 8756 ∴ -
sim 8764 ∼ -
cong 8773 ≅ -
asymp 8776 ≈ -
ne 8800 ≠ -
equiv 8801 ≡ -
le 8804 ≤ -
ge 8805 ≥ -
sub 8834 ⊂ -
sup 8835 ⊃ -
nsub 8836 ⊄ -
sube 8838 ⊆ -
supe 8839 ⊇ -
oplus 8853 ⊕ -
otimes 8855 ⊗ -
perp 8869 ⊥ -
sdot 8901 ⋅ -
lceil 8968 ⌈ -
rceil 8969 ⌉ -
lfloor 8970 ⌊ -
rfloor 8971 ⌋ -
lang 9001 ⟨ -
rang 9002 ⟩ -
loz 9674 ◊ -
spades 9824 ♠ -
clubs 9827 ♣ -
hearts 9829 ♥ -
diams 9830 ♦ - -
-
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Named Character Entities + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Named Character Entities

+ + These are the character entity names supported by D. +

+ + Note: Not all will display properly in the Symbol + column in all browsers. +

+ + + +

+ +
Name Value Symbol + +
quot 34 " +
amp 38 & +
lt 60 < +
gt 62 > + +
OElig 338 Œ +
oelig 339 œ +
Scaron 352 Š +
scaron 353 š +
Yuml 376 Ÿ +
circ 710 ˆ +
tilde 732 ˜ +
ensp 8194   +
emsp 8195   +
thinsp 8201   +
zwnj 8204 ‌ +
zwj 8205 ‍ +
lrm 8206 ‎ +
rlm 8207 ‏ +
ndash 8211 – +
mdash 8212 — +
lsquo 8216 ‘ +
rsquo 8217 ’ +
sbquo 8218 ‚ +
ldquo 8220 “ +
rdquo 8221 ” +
bdquo 8222 „ +
dagger 8224 † +
Dagger 8225 ‡ +
permil 8240 ‰ +
lsaquo 8249 ‹ +
rsaquo 8250 › +
euro 8364 € + + + +
nbsp 160   +
iexcl 161 ¡ +
cent 162 ¢ +
pound 163 £ +
curren 164 ¤ +
yen 165 ¥ +
brvbar 166 ¦ +
sect 167 § +
uml 168 ¨ +
copy 169 © +
ordf 170 ª +
laquo 171 « +
not 172 ¬ +
shy 173 ­ +
reg 174 ® +
macr 175 ¯ +
deg 176 ° +
plusmn 177 ± +
sup2 178 ² +
sup3 179 ³ +
acute 180 ´ +
micro 181 µ +
para 182 ¶ +
middot 183 · +
cedil 184 ¸ +
sup1 185 ¹ +
ordm 186 º +
raquo 187 » +
frac14 188 ¼ +
frac12 189 ½ +
frac34 190 ¾ +
iquest 191 ¿ +
Agrave 192 À +
Aacute 193 Á +
Acirc 194 Â +
Atilde 195 Ã +
Auml 196 Ä +
Aring 197 Å +
AElig 198 Æ +
Ccedil 199 Ç +
Egrave 200 È +
Eacute 201 É +
Ecirc 202 Ê +
Euml 203 Ë +
Igrave 204 Ì +
Iacute 205 Í +
Icirc 206 Î +
Iuml 207 Ï +
ETH 208 Ð +
Ntilde 209 Ñ +
Ograve 210 Ò +
Oacute 211 Ó +
Ocirc 212 Ô +
Otilde 213 Õ +
Ouml 214 Ö +
times 215 × +
Oslash 216 Ø +
Ugrave 217 Ù +
Uacute 218 Ú +
Ucirc 219 Û +
Uuml 220 Ü +
Yacute 221 Ý +
THORN 222 Þ +
szlig 223 ß +
agrave 224 à +
aacute 225 á +
acirc 226 â +
atilde 227 ã +
auml 228 ä +
aring 229 å +
aelig 230 æ +
ccedil 231 ç +
egrave 232 è +
eacute 233 é +
ecirc 234 ê +
euml 235 ë +
igrave 236 ì +
iacute 237 í +
icirc 238 î +
iuml 239 ï +
eth 240 ð +
ntilde 241 ñ +
ograve 242 ò +
oacute 243 ó +
ocirc 244 ô +
otilde 245 õ +
ouml 246 ö +
divide 247 ÷ +
oslash 248 ø +
ugrave 249 ù +
uacute 250 ú +
ucirc 251 û +
uuml 252 ü +
yacute 253 ý +
thorn 254 þ +
yuml 255 ÿ + + + +
fnof 402 ƒ +
Alpha 913 Α +
Beta 914 Β +
Gamma 915 Γ +
Delta 916 Δ +
Epsilon 917 Ε +
Zeta 918 Ζ +
Eta 919 Η +
Theta 920 Θ +
Iota 921 Ι +
Kappa 922 Κ +
Lambda 923 Λ +
Mu 924 Μ +
Nu 925 Ν +
Xi 926 Ξ +
Omicron 927 Ο +
Pi 928 Π +
Rho 929 Ρ +
Sigma 931 Σ +
Tau 932 Τ +
Upsilon 933 Υ +
Phi 934 Φ +
Chi 935 Χ +
Psi 936 Ψ +
Omega 937 Ω +
alpha 945 α +
beta 946 β +
gamma 947 γ +
delta 948 δ +
epsilon 949 ε +
zeta 950 ζ +
eta 951 η +
theta 952 θ +
iota 953 ι +
kappa 954 κ +
lambda 955 λ +
mu 956 μ +
nu 957 ν +
xi 958 ξ +
omicron 959 ο +
pi 960 π +
rho 961 ρ +
sigmaf 962 ς +
sigma 963 σ +
tau 964 τ +
upsilon 965 υ +
phi 966 φ +
chi 967 χ +
psi 968 ψ +
omega 969 ω +
thetasym 977 ϑ +
upsih 978 ϒ +
piv 982 ϖ +
bull 8226 • +
hellip 8230 … +
prime 8242 ′ +
Prime 8243 ″ +
oline 8254 ‾ +
frasl 8260 ⁄ +
weierp 8472 ℘ +
image 8465 ℑ +
real 8476 ℜ +
trade 8482 ™ +
alefsym 8501 ℵ +
larr 8592 ← +
uarr 8593 ↑ +
rarr 8594 → +
darr 8595 ↓ +
harr 8596 ↔ +
crarr 8629 ↵ +
lArr 8656 ⇐ +
uArr 8657 ⇑ +
rArr 8658 ⇒ +
dArr 8659 ⇓ +
hArr 8660 ⇔ +
forall 8704 ∀ +
part 8706 ∂ +
exist 8707 ∃ +
empty 8709 ∅ +
nabla 8711 ∇ +
isin 8712 ∈ +
notin 8713 ∉ +
ni 8715 ∋ +
prod 8719 ∏ +
sum 8721 ∑ +
minus 8722 − +
lowast 8727 ∗ +
radic 8730 √ +
prop 8733 ∝ +
infin 8734 ∞ +
ang 8736 ∠ +
and 8743 ∧ +
or 8744 ∨ +
cap 8745 ∩ +
cup 8746 ∪ +
int 8747 ∫ +
there4 8756 ∴ +
sim 8764 ∼ +
cong 8773 ≅ +
asymp 8776 ≈ +
ne 8800 ≠ +
equiv 8801 ≡ +
le 8804 ≤ +
ge 8805 ≥ +
sub 8834 ⊂ +
sup 8835 ⊃ +
nsub 8836 ⊄ +
sube 8838 ⊆ +
supe 8839 ⊇ +
oplus 8853 ⊕ +
otimes 8855 ⊗ +
perp 8869 ⊥ +
sdot 8901 ⋅ +
lceil 8968 ⌈ +
rceil 8969 ⌉ +
lfloor 8970 ⌊ +
rfloor 8971 ⌋ +
lang 9001 ⟨ +
rang 9002 ⟩ +
loz 9674 ◊ +
spades 9824 ♠ +
clubs 9827 ♣ +
hearts 9829 ♥ +
diams 9830 ♦ + +
+
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/enum.html dmd-0.124/dmd/html/d/enum.html --- dmd-0.123/dmd/html/d/enum.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/enum.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,142 +1,166 @@ - - - - - -D Programming Language - Enums - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last modified Jan 21, 2005. -


- -

Enums - Enumerated Types

- -
-	EnumDeclaration:
-		enum Identifier EnumBody
-		enum EnumBody
-		enum Identifier : EnumBaseType EnumBody
-		enum : EnumBaseType EnumBody
-
-	EnumBaseType:
-		Type
-
-	EnumBody:
-		;
-		{ EnumMembers }
-
-	EnumMembers:
-		EnumMember
-		EnumMember ,
-		EnumMember , EnumMembers
-
-	EnumMember:
-		Identifier
-		Identifier = Expression
-	
- - Enums are used to define a group of related integral constants. -

- - If the enum Identifier is present, the EnumMembers - are declared in the scope of the enum Identifier. - The enum Identifier declares a new type. -

- - If the enum Identifier is not present, then the enum - is an anonymous enum, and the EnumMembers are declared - in the scope the EnumDeclaration appears in. - No new type is created; the EnumMembers have the type of the - EnumBaseType. -

- - The EnumBaseType is the underlying type of the enum. - It must be an integral type. - If omitted, it defaults to int. - -

-	enum { A, B, C }	// anonymous enum
-	
- - 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 }	// named enum
-	
- - 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. -

- - If an Expression is supplied for an enum member, the value - of the member is set to the result of the Expression. - The Expression must be resolvable at compile time. - Subsequent enum members with no Expression are set to the - value of the previous member plus one: - -

-	enum { A, B = 5+7, C, D = 8, E }
-	
- - Sets A=0, B=12, C=13, D=8, and E=9. - -

Enum Properties

- -
-	.min			Smallest value of enum
-	.max			Largest value of enum
-	.sizeof			Size of storage for an enumerated value
-
-	For example:
-
-	X.min			is X.A
-	X.max			is X.C
-	X.sizeof		is same as int.sizeof
-
- -

Initialization of Enums

- - In the absence of an explicit initializer, an enum variable - is initialized to the first enum value. - -
-	enum X { A=3, B, C }
-	X x;		// x is initialized to 3
-	
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Enums + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Enums - Enumerated Types

+ +
+	EnumDeclaration:
+		enum Identifier EnumBody
+		enum EnumBody
+		enum Identifier : EnumBaseType EnumBody
+		enum : EnumBaseType EnumBody
+
+	EnumBaseType:
+		Type
+
+	EnumBody:
+		;
+		{ EnumMembers }
+
+	EnumMembers:
+		EnumMember
+		EnumMember ,
+		EnumMember , EnumMembers
+
+	EnumMember:
+		Identifier
+		Identifier = Expression
+	
+ + Enums are used to define a group of related integral constants. +

+ + If the enum Identifier is present, the EnumMembers + are declared in the scope of the enum Identifier. + The enum Identifier declares a new type. +

+ + If the enum Identifier is not present, then the enum + is an anonymous enum, and the EnumMembers are declared + in the scope the EnumDeclaration appears in. + No new type is created; the EnumMembers have the type of the + EnumBaseType. +

+ + The EnumBaseType is the underlying type of the enum. + It must be an integral type. + If omitted, it defaults to int. + +

+	enum { A, B, C }	// anonymous enum
+	
+ + 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 }	// named enum
+	
+ + 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. +

+ + If an Expression is supplied for an enum member, the value + of the member is set to the result of the Expression. + The Expression must be resolvable at compile time. + Subsequent enum members with no Expression are set to the + value of the previous member plus one: + +

+	enum { A, B = 5+7, C, D = 8, E }
+	
+ + Sets A=0, B=12, C=13, D=8, and E=9. + +

Enum Properties

+ +
+	.min			Smallest value of enum
+	.max			Largest value of enum
+	.sizeof			Size of storage for an enumerated value
+
+	For example:
+
+	X.min			is X.A
+	X.max			is X.C
+	X.sizeof		is same as int.sizeof
+
+ +

Initialization of Enums

+ + In the absence of an explicit initializer, an enum variable + is initialized to the first enum value. + +
+	enum X { A=3, B, C }
+	X x;		// x is initialized to 3
+	
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/errors.html dmd-0.124/dmd/html/d/errors.html --- dmd-0.123/dmd/html/d/errors.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/errors.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,232 +1,258 @@ - - - - - -Digital Mars - The D Programming Language - Errors - - - -www.digitalmars.com -[Home] -[Search] -[D] -


- -

Error Handling in D

- -All programs have to deal with errors. Errors are unexpected conditions that -are not part of the normal operation of a program. Examples of common errors -are: - - - -

The Error Handling Problem

- -The traditional C way of detecting and reporting errors is not traditional, -it is ad-hoc and varies from function to function, including: - - - -To deal with these possible errors, tedious error handling code must be added -to each function call. If an error happened, code must be written to recover -from the error, and the error must be reported to the user in some user friendly -fashion. If an error cannot be handled locally, it must be explicitly -propagated back to its caller. -The long list of errno values needs to be converted into appropriate -text to be displayed. Adding all the code to do this can consume a large part -of the time spent coding a project - and still, if a new errno value is added -to the runtime system, the old code can not properly display a meaningful -error message. -

- -Good error handling code tends to clutter up what otherwise would be a neat -and clean looking implementation. -

- -Even worse, good error handling code is itself error prone, tends to be the -least tested (and therefore buggy) part of the project, and is frequently -simply omitted. The end result is likely a "blue screen of death" as the -program failed to deal with some unanticipated error. -

- -Quick and dirty programs are not worth writing tedious error handling code -for, and so such utilities tend to be like using a table saw with no -blade guards. -

- -What's needed is an error handling philosophy and methodology that is: - -

- -

The D Error Handling Solution

- -Let's first make some observations and assumptions about errors: - - - -The solution is to use exception handling to report errors. All errors are -objects derived from abstract class Error. class Error has a pure virtual -function called toString() which produces a char[] with a human readable -description of the error. -

- -If code detects an error like "out of memory," then an Error is thrown -with a message saying "Out of memory". The function call stack is unwound, -looking for a handler for the Error. Finally blocks are executed as the -stack is unwound. If an error handler is found, execution resumes there. If -not, the default Error handler is run, which displays the message and -terminates the program. -

- -How does this meet our criteria? - -

-
Standardized - consistent usage makes it more useful. -
This is the D way, and is used consistently in the D - runtime library and examples. - -
Produces a reasonable result even if the programmer fails - to check for errors. -
If no catch handlers are there for the errors, then the - program gracefully exits through the default error handler - with an appropriate message. - -
Allows old code to be reused with new code without having - to modify the old code to be compatible with new error types. -
Old code can decide to catch all errors, or only specific ones, - propagating the rest upwards. In any case, there is no more - need to correlate error numbers with messages, the correct message - is always supplied. - -
No errors get inadvertently ignored. -
Error exceptions get handled one way or another. There is nothing - like a NULL pointer return indicating an error, followed by trying to - use that NULL pointer. - -
Allows 'quick and dirty' utilities to be written that still - correctly handle errors. -
Quick and dirty code need not write any error handling code at - all, and don't need to check for errors. The errors will be caught, - an appropriate message displayed, and the program gracefully shut down - all by default. - -
Easy to make the error handling source code look good. -
The try/catch/finally statements look a lot nicer than endless - if (error) goto errorhandler; statements. -
- -How does this meet our assumptions about errors? - -
-
Errors are not part of the normal flow of a program. Errors - are exceptional, unusual, and unexpected. -
D exception handling fits right in with that. - -
Because errors are unusual, execution of error handling code - is not performance critical. -
Exception handling stack unwinding is a relatively slow process. - -
The normal flow of program logic is performance critical. -
Since the normal flow code does not have to check every - function call for error returns, it can be realistically faster - to use exception handling for the errors. - -
All errors must be dealt with in some way, either by - code explicitly written to handle them, or by some system default - handling. -
If there's no handler for a particular error, it is handled - by the runtime library default handler. If an error is ignored, - it is because the programmer specifically added code to ignore - an error, which presumably means it was intentional. - -
The code that detects an error knows more about the error - than the code that must recover from the error. -
There is no more need to translate error codes into human - readable strings, the correct string is generated by the error - detection code, not the error recovery code. This also leads to - consistent error messages for the same error between applications. -
- - - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright (c) 1999-2001 by Digital Mars, All Rights Reserved - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Errors + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

Error Handling in D

+ +All programs have to deal with errors. Errors are unexpected conditions that +are not part of the normal operation of a program. Examples of common errors +are: + + + +

The Error Handling Problem

+ +The traditional C way of detecting and reporting errors is not traditional, +it is ad-hoc and varies from function to function, including: + + + +To deal with these possible errors, tedious error handling code must be added +to each function call. If an error happened, code must be written to recover +from the error, and the error must be reported to the user in some user friendly +fashion. If an error cannot be handled locally, it must be explicitly +propagated back to its caller. +The long list of errno values needs to be converted into appropriate +text to be displayed. Adding all the code to do this can consume a large part +of the time spent coding a project - and still, if a new errno value is added +to the runtime system, the old code can not properly display a meaningful +error message. +

+ +Good error handling code tends to clutter up what otherwise would be a neat +and clean looking implementation. +

+ +Even worse, good error handling code is itself error prone, tends to be the +least tested (and therefore buggy) part of the project, and is frequently +simply omitted. The end result is likely a "blue screen of death" as the +program failed to deal with some unanticipated error. +

+ +Quick and dirty programs are not worth writing tedious error handling code +for, and so such utilities tend to be like using a table saw with no +blade guards. +

+ +What's needed is an error handling philosophy and methodology that is: + +

+ +

The D Error Handling Solution

+ +Let's first make some observations and assumptions about errors: + + + +The solution is to use exception handling to report errors. All errors are +objects derived from abstract class Error. class Error has a pure virtual +function called toString() which produces a char[] with a human readable +description of the error. +

+ +If code detects an error like "out of memory," then an Error is thrown +with a message saying "Out of memory". The function call stack is unwound, +looking for a handler for the Error. Finally blocks are executed as the +stack is unwound. If an error handler is found, execution resumes there. If +not, the default Error handler is run, which displays the message and +terminates the program. +

+ +How does this meet our criteria? + +

+
Standardized - consistent usage makes it more useful. +
This is the D way, and is used consistently in the D + runtime library and examples. + +
Produces a reasonable result even if the programmer fails + to check for errors. +
If no catch handlers are there for the errors, then the + program gracefully exits through the default error handler + with an appropriate message. + +
Allows old code to be reused with new code without having + to modify the old code to be compatible with new error types. +
Old code can decide to catch all errors, or only specific ones, + propagating the rest upwards. In any case, there is no more + need to correlate error numbers with messages, the correct message + is always supplied. + +
No errors get inadvertently ignored. +
Error exceptions get handled one way or another. There is nothing + like a NULL pointer return indicating an error, followed by trying to + use that NULL pointer. + +
Allows 'quick and dirty' utilities to be written that still + correctly handle errors. +
Quick and dirty code need not write any error handling code at + all, and don't need to check for errors. The errors will be caught, + an appropriate message displayed, and the program gracefully shut down + all by default. + +
Easy to make the error handling source code look good. +
The try/catch/finally statements look a lot nicer than endless + if (error) goto errorhandler; statements. +
+ +How does this meet our assumptions about errors? + +
+
Errors are not part of the normal flow of a program. Errors + are exceptional, unusual, and unexpected. +
D exception handling fits right in with that. + +
Because errors are unusual, execution of error handling code + is not performance critical. +
Exception handling stack unwinding is a relatively slow process. + +
The normal flow of program logic is performance critical. +
Since the normal flow code does not have to check every + function call for error returns, it can be realistically faster + to use exception handling for the errors. + +
All errors must be dealt with in some way, either by + code explicitly written to handle them, or by some system default + handling. +
If there's no handler for a particular error, it is handled + by the runtime library default handler. If an error is ignored, + it is because the programmer specifically added code to ignore + an error, which presumably means it was intentional. + +
The code that detects an error knows more about the error + than the code that must recover from the error. +
There is no more need to translate error codes into human + readable strings, the correct string is generated by the error + detection code, not the error recovery code. This also leads to + consistent error messages for the same error between applications. +
+ + + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/expression.html dmd-0.124/dmd/html/d/expression.html --- dmd-0.123/dmd/html/d/expression.html 2005-04-24 01:47:14.000000000 +0200 +++ dmd-0.124/dmd/html/d/expression.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,1105 +1,1209 @@ - - - - - -D Programming Language - Expressions - - - -www.digitalmars.com -[Home] -[Search] -[D] - -
Last update Mar 19, 2005 -


- -

Expressions

- - C and C++ programmers will find the D expressions very familiar, - with a few interesting additions. -

- - Expressions are used to compute values with a resulting type. - These values can then be assigned, - tested, or ignored. Expressions can also have side effects. - -

-	Expression:
-		AssignExpression
-		AssignExpression , Expression
-
-	AssignExpression:
-		ConditionalExpression
-		ConditionalExpression = AssignExpression
-		ConditionalExpression += AssignExpression
-		ConditionalExpression -= AssignExpression
-		ConditionalExpression *= AssignExpression
-		ConditionalExpression /= AssignExpression
-		ConditionalExpression %= AssignExpression
-		ConditionalExpression &= AssignExpression
-		ConditionalExpression |= AssignExpression
-		ConditionalExpression ^= AssignExpression
-		ConditionalExpression ~= AssignExpression
-		ConditionalExpression <<= AssignExpression
-		ConditionalExpression >>= AssignExpression
-		ConditionalExpression >>>= AssignExpression
-
-	ConditionalExpression:
-		OrOrExpression
-		OrOrExpression ? Expression : ConditionalExpression
-
-	OrOrExpression:
-		AndAndExpression
-		OrOrExpression || AndAndExpression
-
-	AndAndExpression:
-		OrExpression
-		AndAndExpression && OrExpression
-
-	OrExpression:
-		XorExpression
-		OrExpression | XorExpression
-
-	XorExpression:
-		AndExpression
-		XorExpression ^ AndExpression
-
-	AndExpression:
-		EqualExpression
-		AndExpression & EqualExpression
-
-	EqualExpression:
-		RelExpression
-		EqualExpression == RelExpression
-		EqualExpression != RelExpression
-		EqualExpression is RelExpression
-
-	RelExpression:
-		ShiftExpression
-		InExpression
-		RelExpression < ShiftExpression
-		RelExpression <= ShiftExpression
-		RelExpression > ShiftExpression
-		RelExpression >= ShiftExpression
-		RelExpression !<>= ShiftExpression
-		RelExpression !<> ShiftExpression
-		RelExpression <> ShiftExpression
-		RelExpression <>= ShiftExpression
-		RelExpression !> ShiftExpression
-		RelExpression !>= ShiftExpression
-		RelExpression !< ShiftExpression
-		RelExpression !<= ShiftExpression
-
-	InExpression:
-		RelExpression in ShiftExpression
-
-	ShiftExpression:
-		AddExpression
-		ShiftExpression << AddExpression
-		ShiftExpression >> AddExpression
-		ShiftExpression >>> AddExpression
-
-	AddExpression:
-		MulExpression
-		AddExpression + MulExpression
-		AddExpression - MulExpression
-		AddExpression ~ MulExpression
-
-	MulExpression:
-		UnaryExpression
-		MulExpression * UnaryExpression
-		MulExpression / UnaryExpression
-		MulExpression % UnaryExpression
-
-	UnaryExpression:
-		PostfixExpression
-		& UnaryExpression
-		++ UnaryExpression
-		-- UnaryExpression
-		* UnaryExpression
-		- UnaryExpression
-		+ UnaryExpression
-		! UnaryExpression
-		~ UnaryExpression
-		delete UnaryExpression
-		NewExpression
-		cast ( Type ) UnaryExpression
-		( Type ) . Identifier
-		( Expression )
-
-	PostfixExpression:
-		PrimaryExpression
-		PostfixExpression . Identifier
-		PostfixExpression ++
-		PostfixExpression --
-		PostfixExpression ( ArgumentList )
-		IndexExpression
-		SliceExpression
-
-	IndexExpression:
-		PostfixExpression [ ArgumentList ]
-
-	SliceExpression:
-		PostfixExpression [ AssignExpression .. AssignExpression ]
-
-	PrimaryExpression:
-		Identifier
-		.Identifier
-		this
-		super
-		null
-		true
-		false
-		NumericLiteral
-		CharacterLiteral
-		StringLiteral
-		FunctionLiteral
-		AssertExpression
-		BasicType . Identifier
-		typeid ( Type )
-
-	AssertExpression:
-		assert ( Expression )
-
-	ArgumentList:
-		AssignExpression
-		AssignExpression , ArgumentList
-
-	NewExpression:
-		new BasicType Stars [ AssignExpression ] Declarator
-		new BasicType Stars ( ArgumentList )
-		new BasicType Stars
-		new ( ArgumentList ) BasicType Stars [ AssignExpression ] Declarator
-		new ( ArgumentList ) BasicType Stars ( ArgumentList )
-		new ( ArgumentList ) BasicType Stars
-
-	Stars
-		nothing
-		*
-		* Stars
-
- -

Evaluation Order

- - Unless otherwise specified, the implementation is free to evaluate - the components of an expression in any order. It is an error - to depend on order of evaluation when it is not specified. - For example, the following are illegal: -
-	i = ++i;
-	c = a + (a = b);
-	func(++i, ++i);
-	
- If the compiler can determine that the result of an expression - is illegally dependent on the order of evaluation, it can issue - an error (but is not required to). The ability to detect these kinds - of errors is a quality of implementation issue. - -

Expressions

- -
-	AssignExpression , Expression
-	
- - The left operand of the , is evaluated, then the right operand - is evaluated. The type of the expression is the type of the right - operand, and the result is the result of the right operand. - - -

Assign Expressions

- -
-	ConditionalExpression = AssignExpression
-	
- - The right operand is implicitly converted to the type of the - left operand, and assigned to it. The result type is the type - of the lvalue, and the result value is the value of the lvalue - after the assignment. -

- - The left operand must be an lvalue. - -

Assignment Operator Expressions

- -
-	ConditionalExpression += AssignExpression
-	ConditionalExpression -= AssignExpression
-	ConditionalExpression *= AssignExpression
-	ConditionalExpression /= AssignExpression
-	ConditionalExpression %= AssignExpression
-	ConditionalExpression &= AssignExpression
-	ConditionalExpression |= AssignExpression
-	ConditionalExpression ^= AssignExpression
-	ConditionalExpression <<= AssignExpression
-	ConditionalExpression >>= AssignExpression
-	ConditionalExpression >>>= AssignExpression
-	
- - Assignment operator expressions, such as: - -
-	a op= b
-	
- - are semantically equivalent to: - -
-	a = a op b
-	
- - except that operand a is only evaluated once. - -

Conditional Expressions

- -
-	OrOrExpression ? Expression : ConditionalExpression
-	
- - The first expression is converted to bool, and is evaluated. - If it is true, then the second expression is evaluated, and - its result is the result of the conditional expression. - If it is false, then the third expression is evaluated, and - its result is the result of the conditional expression. - If either the second or third expressions are of type void, - then the resulting type is void. Otherwise, the second and third - expressions are implicitly converted to a common type which becomes - the result type of the conditional expression. - -

OrOr Expressions

- -
-	OrOrExpression || AndAndExpression
-	
- - The result type of an OrOr expression is bool, unless the right operand - has type void, when the result is type void. -

- - The OrOr expression evaluates its left operand. - - If the left operand, converted to type bool, evaluates to - true, then the right operand is not evaluated. If the result type of - the OrOr expression is bool then the result of the - expression is true. - - If the left operand is false, then the right - operand is evaluated. - If the result type of - the OrOr expression is bool then the result of the - expression is the right operand converted to type bool. - - -

AndAnd Expressions

- -
-	AndAndExpression && OrExpression
-	
- - The result type of an AndAnd expression is bool, unless the right operand - has type void, when the result is type void. -

- - The AndAnd expression evaluates its left operand. - - If the left operand, converted to type bool, evaluates to - false, then the right operand is not evaluated. If the result type of - the AndAnd expression is bool then the result of the - expression is false. - - If the left operand is true, then the right - operand is evaluated. - If the result type of - the AndAnd expression is bool then the result of the - expression is the right operand converted to type bool. - - -

Bitwise Expressions

- - Bit wise expressions perform a bitwise operation on their operands. - Their operands must be integral types. - First, the default integral promotions are done. Then, the bitwise - operation is done. - -

Or Expressions

- -
-	OrExpression | XorExpression
-	
- - The operands are OR'd together. - -

Xor Expressions

- -
-	XorExpression ^ AndExpression
-	
- - The operands are XOR'd together. - -

And Expressions

- -
-	AndExpression & EqualExpression
-	
- - The operands are AND'd together. - - -

Equality Expressions

- -
-	EqualExpression == RelExpression
-	EqualExpression != RelExpression
-	EqualExpression is RelExpression
-	
- - Equality expressions compare the two operands for equality (==) - or inequality (!=). - The type of the result is bool. The operands - go through the usual conversions to bring them to a common type before - comparison. -

- - If they are integral values or pointers, equality - is defined as the bit pattern of the type matches exactly. - Equality for struct objects means the bit patterns of the objects - match exactly (the existence of alignment holes in the objects - is accounted for, usually by setting them all to 0 upon - initialization). - Equality for floating point types is more complicated. -0 and - +0 compare as equal. If either or both operands are NAN, then - both the == and != comparisons return false. Otherwise, the bit - patterns are compared for equality. -

- - For complex numbers, equality is defined as equivalent to: - -

-	x.re == y.re && x.im == y.im
-	
- - and inequality is defined as equivalent to: - -
-	x.re != y.re || x.im != y.im
-	
- - For class and struct objects, the expression (a == b) - is rewritten as - a.opEquals(b), and (a != b) is rewritten as - !a.opEquals(b). -

- - For static and dynamic arrays, equality is defined as the - lengths of the arrays - matching, and all the elements are equal. - - -

Identity Expressions

- -
-	EqualExpression is RelExpression
-	
- - The is compares for identity. - To compare for not identity, use !(e1 is e2). - The type of the result is bool. The operands - go through the usual conversions to bring them to a common type before - comparison. -

- - For operand types other than class objects, static or dynamic arrays, - identity is defined as being the same as equality. -

- - For class objects, identity is defined as the object references - are for the same object. Null class objects can be compared with - is. -

- - For static and dynamic arrays, identity is defined as referring - to the same array elements. -

- - The identity operator is cannot be overloaded. - -

Relational Expressions

- -
-	RelExpression < ShiftExpression
-	RelExpression <= ShiftExpression
-	RelExpression > ShiftExpression
-	RelExpression >= ShiftExpression
-	RelExpression !<>= ShiftExpression
-	RelExpression !<> ShiftExpression
-	RelExpression <> ShiftExpression
-	RelExpression <>= ShiftExpression
-	RelExpression !> ShiftExpression
-	RelExpression !>= ShiftExpression
-	RelExpression !< ShiftExpression
-	RelExpression !<= ShiftExpression
-	
- - First, the integral promotions are done on the operands. - The result type of a relational expression is bool. -

- - For class objects, the result of Object.opCmp() forms the left - operand, and 0 forms the right operand. The result of the - relational expression (o1 op o2) is: -

-	(o1.opCmp(o2) op 0)
-	
- It is an error to compare objects if one is null. -

- - For static and dynamic arrays, the result of the relational - op is the result of the operator applied to the first non-equal - element of the array. If two arrays compare equal, but are of - different lengths, the shorter array compares as "less" than the - longer array. - - -

Integer comparisons

- - Integer comparisons happen when both operands are integral - types. -

- - - - - - - - - - - - - - - - - - -
Integer comparison operators
OperatorRelation
< less
> greater
<= less or equal
>= greater or equal
== equal
!= not equal
-

- - It is an error to have one operand be signed and the other - unsigned for a <, <=, > or >= expression. - Use casts to make both operands signed or both operands unsigned. - -

Floating point comparisons

- - If one or both operands are floating point, then a floating - point comparison is performed. -

- - Useful floating point operations must take into account NAN values. - In particular, a relational operator can have NAN operands. - The result of a relational operation on float - values is less, greater, equal, or unordered (unordered means - either or both of the - operands is a NAN). That means there are 14 possible comparison - conditions to test for: -

- - - - - - - - - - - - - - - - - - -
Floating point comparison operators
Operator - Greater Than - Less Than - Equal - Unordered - Exception - Relation - -
== F F T F no equal - -
!= T T F T no unordered, less, or greater - -
> T F F F yes greater - -
>= T F T F yes greater or equal - -
< F T F F yes less - -
<= F T T F yes less or equal - -
!<>= F F F T no unordered - -
<> T T F F yes less or greater - -
<>= T T T F yes less, equal, or greater - -
!<= T F F T no unordered or greater - -
!< T F T T no unordered, greater, or equal - -
!>= F T F T no unordered or less - -
!> F T T T no unordered, less, or equal - -
!<> F F T T no unordered or equal - -
- -

Notes:

-
    -
  1. For floating point comparison operators, (a !op b) is not the same as !(a op b). -
  2. "Unordered" means one or both of the operands is a NAN. -
  3. "Exception" means the Invalid Exception is raised if one - of the operands is a NAN. -
- -

In Expressions

- -
-	RelExpression in ShiftExpression
-	
- - An associative array can be tested to see if an element is in the array: - -
-	int foo[char[]];
-	.
-	if ("hello" in foo)
-		.
-	
- - The in expression has the same precedence as the - relational expressions <, <=, - etc. - The return value of the InExpression is null - if the element is not in the array; - if it is in the array it is a pointer to the element. - -

Shift Expressions

- -
-	ShiftExpression << AddExpression
-	ShiftExpression >> AddExpression
-	ShiftExpression >>> AddExpression
-	
- - The operands must be integral types, and undergo the usual integral - promotions. The result type is the type of the left operand after - the promotions. The result value is the result of shifting the bits - by the right operand's value. -

- - << is a left shift. - >> is a signed right shift. - >>> is an unsigned right shift. -

- - It's illegal to shift by more bits than the size of the - quantity being shifted: - -

-	int c;
-	c << 33;	error
-	
- -

Add Expressions

- -
-	AddExpression + MulExpression
-	AddExpression - MulExpression
-	AddExpression ~ MulExpression
-	
- - If the operands are of integral types, they undergo integral - promotions, and then are brought to a common type using the - usual arithmetic conversions. -

- - If either operand is a floating point type, the other is implicitly - converted to floating point and they are brought to a common type - via the usual arithmetic conversions. -

- - If the operator is + or -, and - the first operand is a pointer, and the second is an integral type, - the resulting type is the type of the first operand, and the resulting - value is the pointer plus (or minus) the second operand multiplied by - the size of the type pointed to by the first operand. -

- - If it is a pointer to a bit, the second operand is divided by 8 - and added to the pointer. It is illegal if the second operand modulo - 8 is non-zero. - -

-	bit* p;
-	p += 1;		// error, 1%8 is non-zero
-	p += 8;		// ok
-	
- - If the second operand is a pointer, and the first is an integral type, - and the operator is +, - the operands are reversed and the pointer arithmetic just described - is applied. -

- - Add expressions for floating point operands are not associative. - -

Mul Expressions

- -
-	MulExpression * UnaryExpression
-	MulExpression / UnaryExpression
-	MulExpression % UnaryExpression
-	
- - The operands must be arithmetic types. They undergo integral - promotions, and then are brought to a common type using the - usual arithmetic conversions. -

- - For integral operands, the *, /, and % - correspond to multiply, divide, and modulus operations. - For multiply, overflows are ignored and simply chopped to fit - into the integral type. If the right operand of divide or modulus - operators is 0, a DivideByZeroException is thrown. -

- - For floating point operands, the operations correspond to the - IEEE 754 floating point equivalents. The modulus operator only - works with reals, it is illegal to use it with imaginary or complex - operands. -

- - Mul expressions for floating point operands are not associative. - -

Unary Expressions

- -
-	& UnaryExpression
-	++ UnaryExpression
-	-- UnaryExpression
-	* UnaryExpression
-	- UnaryExpression
-	+ UnaryExpression
-	! UnaryExpression
-	~ UnaryExpression
-	delete UnaryExpression
-	NewExpression
-	cast ( Type ) UnaryExpression
-	( Type ) . Identifier
-	( Expression )
-	
- - -

New Expressions

- - New expressions are used to allocate memory on the garbage - collected heap (default) or using a class or struct specific allocator. -

- - To allocate multidimensional arrays, the declaration reads - in the same order as the prefix array declaration order. - -

-	char[][] foo;	// dynamic array of strings
-	...
-	foo = new char[][30];	// allocate 30 arrays of strings
-	
- - If there is an ( ArgumentList ), then - those arguments are passed to the class or struct specific allocator - function after the size argument. - -

Delete Expressions

- - Delete expressions delete memory on the garbage collected - heap, or using a class or struct specific deallocator. - The UnaryExpression must be a reference to a class - object, a pointer to a struct object, a pointer, or - a dynamic array. -

- - The pointer or reference is set to null after the delete - is performed. - -

Cast Expressions

- - In C and C++, cast expressions are of the form: - -
-	(type) unaryexpression
-	
- - There is an ambiguity in the grammar, however. Consider: - -
-		(foo) - p;
-	
- - Is this a cast of a dereference of negated p to type foo, or is it p being subtracted from - foo? This cannot be resolved without looking up foo in the symbol table to see if it is a - type or a variable. But D's design goal is to have the syntax be context free - it needs - to be able to parse the syntax without reference to the symbol table. So, in order to - distinguish a cast from a parenthesized subexpression, a different syntax is necessary. -

- - C++ does this by introducing: - -

-	dynamic_cast<type>(expression)
-	
- - which is ugly and clumsy to type. D introduces the cast keyword: - -
-	cast(foo) -p;	// cast (-p) to type foo
-	(foo) - p;	// subtract p from foo
-	
- - cast has the nice characteristic that it is easy to do - a textual search for it, and takes some - of the burden off of the relentlessly overloaded () operator. -

- - D differs from C/C++ in another aspect of casts. Any casting of a class reference to a - derived class reference is done with a runtime check to make sure it really is a proper - downcast. This means that it is equivalent to the behavior of the dynamic_cast operator in - C++. - -

-	class A { ... }
-	class B : A { ... }
-
-	void test(A a, B b)
-	{
-	     B bx = a;		error, need cast
-	     B bx = cast(B) a;	bx is null if a is not a B
-	     A ax = b;		no cast needed
-	     A ax = cast(A) b;	no runtime check needed for upcast
-	}
-	
- - In order to determine if an object o is an instance of - a class B use a cast: - -
-	if (cast(B) o)
-	{
-	    // o is an instance of B
-	}
-	else
-	{
-	    // o is not an instance of B
-	}
-	
- -

Postfix Expressions

- -
-	PostfixExpression . Identifier
-	PostfixExpression -> Identifier
-	PostfixExpression ++
-	PostfixExpression --
-	PostfixExpression ( ArgumentList )
-	PostfixExpression [ ArgumentList ]
-	PostfixExpression [ AssignExpression .. AssignExpression ]
-	
- -

Index Expressions

- -
-	PostfixExpression [ ArgumentList ]
-	
- - PostfixExpression is evaluated. - if PostfixExpression is an expression of type - static array or dynamic array, the variable length - is declared and set to be the length of the array. - A new declaration scope is created for the evaluation of the - ArgumentList and length appears in that scope only. - - -

Slice Expressions

- -
-	PostfixExpression [ AssignExpression .. AssignExpression ]
-	
- - PostfixExpression is evaluated. - if PostfixExpression is an expression of type - static array or dynamic array, the variable length - is declared and set to be the length of the array. - A new declaration scope is created for the evaluation of the - AssignExpression..AssignExpression - and length appears in that scope only. -

- - The first AssignExpression is taken to be the inclusive - lower bound - of the slice, and the second AssignExpression is the - exclusive upper bound. - The result of the expression is a slice of the PostfixExpression - array. - -

Primary Expressions

- -
-	Identifier
-	.Identifier
-	this
-	super
-	null
-	true
-	false
-	NumericLiteral
-	CharacterLiteral
-	StringLiteral
-	FunctionLiteral
-	AssertExpression
-	BasicType . Identifier
-	typeid ( Type )
-	
- -

.Identifier

- - Identifier is looked up at module scope, rather than the current - lexically nested scope. - -

this

- - Within a non-static member function, this resolves to - a reference to the object that called the function. - If a member function is called with an explicit reference - to typeof(this), a non-virtual call is made: - -
-	class A
-	{
-	    char get() { return 'A'; }
-
-	    char foo() { return typeof(this).get(); }
-	    char bar() { return this.get(); }
-	}
-
-	class B : A
-	{
-	    char get() { return 'B'; }
-	}
-
-	void main()
-	{
-	    B b = new B();
-
-	    b.foo();		// returns 'A'
-	    b.bar();		// returns 'B'
-	}
-	
- - -

super

- - Within a non-static member function, super resolves to - a reference to the object that called the function, cast to - its base class. It is an error if there is no base class. - super is not allowed in struct member - functions. - If a member function is called with an explicit reference - to super, a non-virtual call is made. - -

null

- - The keyword null represents the null pointer value; - technically it is of type (void *). It - can be implicitly cast to any pointer type. - The integer 0 cannot be cast to the null pointer. - Nulls are also used for empty arrays. - -

true, false

- - These are of type bit and resolve to values 1 and 0, - respectively. - -

Character Literals

- - Character literals are single characters and resolve to one - of type char, wchar, or dchar. - If the literal is a \u escape sequence, it resolves to type wchar. - If the literal is a \U escape sequence, it resolves to type dchar. - Otherwise, it resolves to the type with the smallest size it - will fit into. - -

Function Literals

- -
-	FunctionLiteral
-		function FunctionBody
-		function ( ParameterList ) FunctionBody
-		function Type ( ParameterList ) FunctionBody
-		delegate FunctionBody
-		delegate ( ParameterList ) FunctionBody
-		delegate Type ( ParameterList ) FunctionBody
-	
- - FunctionLiterals enable embedding anonymous functions - and anonymous delegates directly into expressions. - Type is the return type of the function or delegate, - if omitted it defaults to void. - ( ParameterList ) forms the parameters to - the function. - If omitted it defaults to the empty parameter list (). - The type of a function literal is pointer to function or - pointer to delegate. -

- - For example: - -

-	int function(char c) fp;	// declare pointer to a function
-
-	void test()
-	{
-	    static int foo(char c) { return 6; }
-
-	    fp = &foo;
-	}
-	
- - is exactly equivalent to: - -
-	int function(char c) fp;
-
-	void test()
-	{
-	    fp = function int(char c) { return 6;} ;
-	}
-	
- - And: - -
-	int abc(int delegate(long i));
-
-	void test()
-	{   int b = 3;
-	    int foo(long c) { return 6 + b; }
-
-	    abc(&foo);
-	}
-	
- - is exactly equivalent to: - -
-	int abc(int delegate(long i));
-
-	void test()
-	{   int b = 3;
-
-	    abc( delegate int(long c) { return 6 + b; } );
-	}
-	
- - Anonymous delegates can behave like arbitrary statement literals. - For example, here an arbitrary statement is executed by a loop: - -
-	double test()
-	{   double d = 7.6;
-	    float f = 2.3;
-
-	    void loop(int k, int j, void delegate() statement)
-	    {
-		for (int i = k; i < j; i++)
-		{
-		    statement();
-		}
-	    }
-
-	    loop(5, 100, delegate { d += 1; } );
-	    loop(3, 10,  delegate { f += 1; } );
-
-	    return d + f;
-	}
-	
- - When comparing with nested - functions, the function form is analogous to static - or non-nested functions, and the delegate form is - analogous to non-static nested functions. In other words, - a delegate literal can access stack variables in its enclosing - function, a function literal cannot. - - -

Assert Expressions

- -
-	AssertExpression:
-		assert ( Expression )
-	
- - Asserts evaluate the expression. If the result is false, - an AssertError is thrown. If the result is true, then no - exception is thrown. - It is an error if the expression contains any side effects - that the program depends on. The compiler may optionally not - evaluate assert expressions at all. - The result type of an assert expression is void. - Asserts are a fundamental part of the - Contract Programming - support in D. -

- - The expression assert(0) is a special case; it - signifies that it is unreachable code. - Either AssertError is thrown at runtime if it is reachable, - or a HLT instruction is executed. - The optimization and code generation phases of compilation may - assume that it is unreachable code. - -

Typeid Expressions

- -
-	TypeidExpression:
-	    typeid ( Type )
-	
- - Returns an instance of class TypeInfo corresponding - to Type. - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved
- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Expressions + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ +

Expressions

+ + C and C++ programmers will find the D expressions very familiar, + with a few interesting additions. +

+ + Expressions are used to compute values with a resulting type. + These values can then be assigned, + tested, or ignored. Expressions can also have side effects. + +

+
+

+	Expression:
+		AssignExpression
+		AssignExpression , Expression
+
+	AssignExpression:
+		ConditionalExpression
+		ConditionalExpression = AssignExpression
+		ConditionalExpression += AssignExpression
+		ConditionalExpression -= AssignExpression
+		ConditionalExpression *= AssignExpression
+		ConditionalExpression /= AssignExpression
+		ConditionalExpression %= AssignExpression
+		ConditionalExpression &= AssignExpression
+		ConditionalExpression |= AssignExpression
+		ConditionalExpression ^= AssignExpression
+		ConditionalExpression ~= AssignExpression
+		ConditionalExpression <<= AssignExpression
+		ConditionalExpression >>= AssignExpression
+		ConditionalExpression >>>= AssignExpression
+
+	ConditionalExpression:
+		OrOrExpression
+		OrOrExpression ? Expression : ConditionalExpression
+
+	OrOrExpression:
+		AndAndExpression
+		OrOrExpression || AndAndExpression
+
+	AndAndExpression:
+		OrExpression
+		AndAndExpression && OrExpression
+
+	OrExpression:
+		XorExpression
+		OrExpression | XorExpression
+
+	XorExpression:
+		AndExpression
+		XorExpression ^ AndExpression
+
+	AndExpression:
+		EqualExpression
+		AndExpression & EqualExpression
+
+	EqualExpression:
+		RelExpression
+		EqualExpression == RelExpression
+		EqualExpression != RelExpression
+		EqualExpression is RelExpression
+
+	RelExpression:
+		ShiftExpression
+		InExpression
+		RelExpression < ShiftExpression
+		RelExpression <= ShiftExpression
+		RelExpression > ShiftExpression
+		RelExpression >= ShiftExpression
+		RelExpression !<>= ShiftExpression
+		RelExpression !<> ShiftExpression
+		RelExpression <> ShiftExpression
+		RelExpression <>= ShiftExpression
+		RelExpression !> ShiftExpression
+		RelExpression !>= ShiftExpression
+		RelExpression !< ShiftExpression
+		RelExpression !<= ShiftExpression
+
+	InExpression:
+		RelExpression in ShiftExpression
+
+	ShiftExpression:
+		AddExpression
+		ShiftExpression << AddExpression
+		ShiftExpression >> AddExpression
+		ShiftExpression >>> AddExpression
+
+	AddExpression:
+		MulExpression
+		AddExpression + MulExpression
+		AddExpression - MulExpression
+		AddExpression ~ MulExpression
+
+	MulExpression:
+		UnaryExpression
+		MulExpression * UnaryExpression
+		MulExpression / UnaryExpression
+		MulExpression % UnaryExpression
+
+	UnaryExpression:
+		PostfixExpression
+		& UnaryExpression
+		++ UnaryExpression
+		-- UnaryExpression
+		* UnaryExpression
+		- UnaryExpression
+		+ UnaryExpression
+		! UnaryExpression
+		~ UnaryExpression
+		delete UnaryExpression
+		NewExpression
+		cast ( Type ) UnaryExpression
+		( Type ) . Identifier
+		( Expression )
+
+	PostfixExpression:
+		PrimaryExpression
+		PostfixExpression . Identifier
+		PostfixExpression ++
+		PostfixExpression --
+		PostfixExpression ( ArgumentList )
+		IndexExpression
+		SliceExpression
+
+	IndexExpression:
+		PostfixExpression [ ArgumentList ]
+
+	SliceExpression:
+		PostfixExpression [ AssignExpression .. AssignExpression ]
+
+	PrimaryExpression:
+		Identifier
+		.Identifier
+		this
+		super
+		null
+		true
+		false
+		NumericLiteral
+		CharacterLiteral
+		StringLiteral
+		FunctionLiteral
+		AssertExpression
+		BasicType . Identifier
+		typeid ( Type )
+
+	AssertExpression:
+		assert ( Expression )
+
+	ArgumentList:
+		AssignExpression
+		AssignExpression , ArgumentList
+
+	NewExpression:
+		new BasicType Stars [ AssignExpression ] Declarator
+		new BasicType Stars ( ArgumentList )
+		new BasicType Stars
+		new ( ArgumentList ) BasicType Stars [ AssignExpression ] Declarator
+		new ( ArgumentList ) BasicType Stars ( ArgumentList )
+		new ( ArgumentList ) BasicType Stars
+
+	Stars
+		nothing
+		*
+		* Stars
+

+ +

Evaluation Order

+ + Unless otherwise specified, the implementation is free to evaluate + the components of an expression in any order. It is an error + to depend on order of evaluation when it is not specified. + For example, the following are illegal: +

+
+

+	i = ++i;
+	c = a + (a = b);
+	func(++i, ++i);
+	

+ If the compiler can determine that the result of an expression + is illegally dependent on the order of evaluation, it can issue + an error (but is not required to). The ability to detect these kinds + of errors is a quality of implementation issue. + +

Expressions

+ +

+
+

+	AssignExpression , Expression
+	

+ + The left operand of the , is evaluated, then the right operand + is evaluated. The type of the expression is the type of the right + operand, and the result is the result of the right operand. + + +

Assign Expressions

+ +

+
+

+	ConditionalExpression = AssignExpression
+	

+ + The right operand is implicitly converted to the type of the + left operand, and assigned to it. The result type is the type + of the lvalue, and the result value is the value of the lvalue + after the assignment. +

+ + The left operand must be an lvalue. + +

Assignment Operator Expressions

+ +

+
+

+	ConditionalExpression += AssignExpression
+	ConditionalExpression -= AssignExpression
+	ConditionalExpression *= AssignExpression
+	ConditionalExpression /= AssignExpression
+	ConditionalExpression %= AssignExpression
+	ConditionalExpression &= AssignExpression
+	ConditionalExpression |= AssignExpression
+	ConditionalExpression ^= AssignExpression
+	ConditionalExpression <<= AssignExpression
+	ConditionalExpression >>= AssignExpression
+	ConditionalExpression >>>= AssignExpression
+	

+ + Assignment operator expressions, such as: + +

+	a op= b
+	
+ + are semantically equivalent to: + +
+	a = a op b
+	
+ + except that operand a is only evaluated once. + +

Conditional Expressions

+ +

+
+

+	OrOrExpression ? Expression : ConditionalExpression
+	

+ + The first expression is converted to bool, and is evaluated. + If it is true, then the second expression is evaluated, and + its result is the result of the conditional expression. + If it is false, then the third expression is evaluated, and + its result is the result of the conditional expression. + If either the second or third expressions are of type void, + then the resulting type is void. Otherwise, the second and third + expressions are implicitly converted to a common type which becomes + the result type of the conditional expression. + +

OrOr Expressions

+ +

+
+

+	OrOrExpression || AndAndExpression
+	

+ + The result type of an OrOr expression is bool, unless the right operand + has type void, when the result is type void. +

+ + The OrOr expression evaluates its left operand. + + If the left operand, converted to type bool, evaluates to + true, then the right operand is not evaluated. If the result type of + the OrOr expression is bool then the result of the + expression is true. + + If the left operand is false, then the right + operand is evaluated. + If the result type of + the OrOr expression is bool then the result of the + expression is the right operand converted to type bool. + + +

AndAnd Expressions

+ +

+
+

+	AndAndExpression && OrExpression
+	

+ + The result type of an AndAnd expression is bool, unless the right operand + has type void, when the result is type void. +

+ + The AndAnd expression evaluates its left operand. + + If the left operand, converted to type bool, evaluates to + false, then the right operand is not evaluated. If the result type of + the AndAnd expression is bool then the result of the + expression is false. + + If the left operand is true, then the right + operand is evaluated. + If the result type of + the AndAnd expression is bool then the result of the + expression is the right operand converted to type bool. + + +

Bitwise Expressions

+ + Bit wise expressions perform a bitwise operation on their operands. + Their operands must be integral types. + First, the default integral promotions are done. Then, the bitwise + operation is done. + +

Or Expressions

+ +

+
+

+	OrExpression | XorExpression
+	

+ + The operands are OR'd together. + +

Xor Expressions

+ +

+
+

+	XorExpression ^ AndExpression
+	

+ + The operands are XOR'd together. + +

And Expressions

+ +

+
+

+	AndExpression & EqualExpression
+	

+ + The operands are AND'd together. + + +

Equality Expressions

+ +

+
+

+	EqualExpression == RelExpression
+	EqualExpression != RelExpression
+	EqualExpression is RelExpression
+	

+ + Equality expressions compare the two operands for equality (==) + or inequality (!=). + The type of the result is bool. The operands + go through the usual conversions to bring them to a common type before + comparison. +

+ + If they are integral values or pointers, equality + is defined as the bit pattern of the type matches exactly. + Equality for struct objects means the bit patterns of the objects + match exactly (the existence of alignment holes in the objects + is accounted for, usually by setting them all to 0 upon + initialization). + Equality for floating point types is more complicated. -0 and + +0 compare as equal. If either or both operands are NAN, then + both the == and != comparisons return false. Otherwise, the bit + patterns are compared for equality. +

+ + For complex numbers, equality is defined as equivalent to: + +

+	x.re == y.re && x.im == y.im
+	
+ + and inequality is defined as equivalent to: + +
+	x.re != y.re || x.im != y.im
+	
+ + For class and struct objects, the expression (a == b) + is rewritten as + a.opEquals(b), and (a != b) is rewritten as + !a.opEquals(b). +

+ + For static and dynamic arrays, equality is defined as the + lengths of the arrays + matching, and all the elements are equal. + + +

Identity Expressions

+ +

+
+

+	EqualExpression is RelExpression
+	

+ + The is compares for identity. + To compare for not identity, use !(e1 is e2). + The type of the result is bool. The operands + go through the usual conversions to bring them to a common type before + comparison. +

+ + For operand types other than class objects, static or dynamic arrays, + identity is defined as being the same as equality. +

+ + For class objects, identity is defined as the object references + are for the same object. Null class objects can be compared with + is. +

+ + For static and dynamic arrays, identity is defined as referring + to the same array elements. +

+ + The identity operator is cannot be overloaded. + +

Relational Expressions

+ +

+
+

+	RelExpression < ShiftExpression
+	RelExpression <= ShiftExpression
+	RelExpression > ShiftExpression
+	RelExpression >= ShiftExpression
+	RelExpression !<>= ShiftExpression
+	RelExpression !<> ShiftExpression
+	RelExpression <> ShiftExpression
+	RelExpression <>= ShiftExpression
+	RelExpression !> ShiftExpression
+	RelExpression !>= ShiftExpression
+	RelExpression !< ShiftExpression
+	RelExpression !<= ShiftExpression
+	

+ + First, the integral promotions are done on the operands. + The result type of a relational expression is bool. +

+ + For class objects, the result of Object.opCmp() forms the left + operand, and 0 forms the right operand. The result of the + relational expression (o1 op o2) is: +

+	(o1.opCmp(o2) op 0)
+	
+ It is an error to compare objects if one is null. +

+ + For static and dynamic arrays, the result of the relational + op is the result of the operator applied to the first non-equal + element of the array. If two arrays compare equal, but are of + different lengths, the shorter array compares as "less" than the + longer array. + + +

Integer comparisons

+ + Integer comparisons happen when both operands are integral + types. +

+ + + + + + + + + + + + + + + + + + +
Integer comparison operators
OperatorRelation
< less
> greater
<= less or equal
>= greater or equal
== equal
!= not equal
+

+ + It is an error to have one operand be signed and the other + unsigned for a <, <=, > or >= expression. + Use casts to make both operands signed or both operands unsigned. + +

Floating point comparisons

+ + If one or both operands are floating point, then a floating + point comparison is performed. +

+ + Useful floating point operations must take into account NAN values. + In particular, a relational operator can have NAN operands. + The result of a relational operation on float + values is less, greater, equal, or unordered (unordered means + either or both of the + operands is a NAN). That means there are 14 possible comparison + conditions to test for: +

+ + + + + + + + + + + + + + + + + + +
Floating point comparison operators
Operator + Greater Than + Less Than + Equal + Unordered + Exception + Relation + +
== F F T F no equal + +
!= T T F T no unordered, less, or greater + +
> T F F F yes greater + +
>= T F T F yes greater or equal + +
< F T F F yes less + +
<= F T T F yes less or equal + +
!<>= F F F T no unordered + +
<> T T F F yes less or greater + +
<>= T T T F yes less, equal, or greater + +
!<= T F F T no unordered or greater + +
!< T F T T no unordered, greater, or equal + +
!>= F T F T no unordered or less + +
!> F T T T no unordered, less, or equal + +
!<> F F T T no unordered or equal + +
+ +

Notes:

+
    +
  1. For floating point comparison operators, (a !op b) is not the same as !(a op b). +
  2. "Unordered" means one or both of the operands is a NAN. +
  3. "Exception" means the Invalid Exception is raised if one + of the operands is a NAN. +
+ +

In Expressions

+ +

+
+

+	RelExpression in ShiftExpression
+	

+ + An associative array can be tested to see if an element is in the array: + +

+
+

+	int foo[char[]];
+	...
+	if ("hello" in foo)
+		...
+	

+ + The in expression has the same precedence as the + relational expressions <, <=, + etc. + The return value of the InExpression is null + if the element is not in the array; + if it is in the array it is a pointer to the element. + +

Shift Expressions

+ +

+
+

+	ShiftExpression << AddExpression
+	ShiftExpression >> AddExpression
+	ShiftExpression >>> AddExpression
+	

+ + The operands must be integral types, and undergo the usual integral + promotions. The result type is the type of the left operand after + the promotions. The result value is the result of shifting the bits + by the right operand's value. +

+ + << is a left shift. + >> is a signed right shift. + >>> is an unsigned right shift. +

+ + It's illegal to shift by more bits than the size of the + quantity being shifted: + +

+
+

+	int c;
+	c << 33;	// error
+	

+ +

Add Expressions

+ +

+
+

+	AddExpression + MulExpression
+	AddExpression - MulExpression
+	AddExpression ~ MulExpression
+	

+ + If the operands are of integral types, they undergo integral + promotions, and then are brought to a common type using the + usual arithmetic conversions. +

+ + If either operand is a floating point type, the other is implicitly + converted to floating point and they are brought to a common type + via the usual arithmetic conversions. +

+ + If the operator is + or -, and + the first operand is a pointer, and the second is an integral type, + the resulting type is the type of the first operand, and the resulting + value is the pointer plus (or minus) the second operand multiplied by + the size of the type pointed to by the first operand. +

+ + If it is a pointer to a bit, the second operand is divided by 8 + and added to the pointer. It is illegal if the second operand modulo + 8 is non-zero. + +

+
+

+	bit* p;
+	p += 1;		// error, 1%8 is non-zero
+	p += 8;		// ok
+	

+ + If the second operand is a pointer, and the first is an integral type, + and the operator is +, + the operands are reversed and the pointer arithmetic just described + is applied. +

+ + Add expressions for floating point operands are not associative. + +

Mul Expressions

+ +

+
+

+	MulExpression * UnaryExpression
+	MulExpression / UnaryExpression
+	MulExpression % UnaryExpression
+	

+ + The operands must be arithmetic types. They undergo integral + promotions, and then are brought to a common type using the + usual arithmetic conversions. +

+ + For integral operands, the *, /, and % + correspond to multiply, divide, and modulus operations. + For multiply, overflows are ignored and simply chopped to fit + into the integral type. If the right operand of divide or modulus + operators is 0, a DivideByZeroException is thrown. +

+ + For floating point operands, the operations correspond to the + IEEE 754 floating point equivalents. The modulus operator only + works with reals, it is illegal to use it with imaginary or complex + operands. +

+ + Mul expressions for floating point operands are not associative. + +

Unary Expressions

+ +

+
+

+	& UnaryExpression
+	++ UnaryExpression
+	-- UnaryExpression
+	* UnaryExpression
+	- UnaryExpression
+	+ UnaryExpression
+	! UnaryExpression
+	~ UnaryExpression
+	delete UnaryExpression
+	NewExpression
+	cast ( Type ) UnaryExpression
+	( Type ) . Identifier
+	( Expression )
+	

+ + +

New Expressions

+ + New expressions are used to allocate memory on the garbage + collected heap (default) or using a class or struct specific allocator. +

+ + To allocate multidimensional arrays, the declaration reads + in the same order as the prefix array declaration order. + +

+
+

+	char[][] foo;	// dynamic array of strings
+	...
+	foo = new char[][30];	// allocate 30 arrays of strings
+	

+ + If there is an ( ArgumentList ), then + those arguments are passed to the class or struct specific allocator + function after the size argument. + +

Delete Expressions

+ + Delete expressions delete memory on the garbage collected + heap, or using a class or struct specific deallocator. + The UnaryExpression must be a reference to a class + object, a pointer to a struct object, a pointer, or + a dynamic array. +

+ + The pointer or reference is set to null after the delete + is performed. + +

Cast Expressions

+ + In C and C++, cast expressions are of the form: + +
+	(type) unaryexpression
+	
+ + There is an ambiguity in the grammar, however. Consider: + +

+
+

+	(foo) - p;
+	

+ + Is this a cast of a dereference of negated p to type foo, or is it p being subtracted from + foo? This cannot be resolved without looking up foo in the symbol table to see if it is a + type or a variable. But D's design goal is to have the syntax be context free - it needs + to be able to parse the syntax without reference to the symbol table. So, in order to + distinguish a cast from a parenthesized subexpression, a different syntax is necessary. +

+ + C++ does this by introducing: + +

+
+

+	dynamic_cast<type>(expression)
+	

+ + which is ugly and clumsy to type. D introduces the cast keyword: + +

+
+

+	cast(foo) -p;	// cast (-p) to type foo
+	(foo) - p;	// subtract p from foo
+	

+ + cast has the nice characteristic that it is easy to do + a textual search for it, and takes some + of the burden off of the relentlessly overloaded () operator. +

+ + D differs from C/C++ in another aspect of casts. Any casting of a class reference to a + derived class reference is done with a runtime check to make sure it really is a proper + downcast. This means that it is equivalent to the behavior of the dynamic_cast operator in + C++. + +

+
+

+	class A { ... }
+	class B : A { ... }
+
+	void test(A a, B b)
+	{
+	     B bx = a;		error, need cast
+	     B bx = cast(B) a;	bx is null if a is not a B
+	     A ax = b;		no cast needed
+	     A ax = cast(A) b;	no runtime check needed for upcast
+	}
+	

+ + In order to determine if an object o is an instance of + a class B use a cast: + +

+
+

+	if (cast(B) o)
+	{
+	    // o is an instance of B
+	}
+	else
+	{
+	    // o is not an instance of B
+	}
+	

+ +

Postfix Expressions

+ +

+
+

+	PostfixExpression . Identifier
+	PostfixExpression -> Identifier
+	PostfixExpression ++
+	PostfixExpression --
+	PostfixExpression ( ArgumentList )
+	PostfixExpression [ ArgumentList ]
+	PostfixExpression [ AssignExpression .. AssignExpression ]
+	

+ +

Index Expressions

+ +

+
+

+	PostfixExpression [ ArgumentList ]
+	

+ + PostfixExpression is evaluated. + if PostfixExpression is an expression of type + static array or dynamic array, the variable length + is declared and set to be the length of the array. + A new declaration scope is created for the evaluation of the + ArgumentList and length appears in that scope only. + + +

Slice Expressions

+ +

+
+

+	PostfixExpression [ AssignExpression .. AssignExpression ]
+	

+ + PostfixExpression is evaluated. + if PostfixExpression is an expression of type + static array or dynamic array, the variable length + is declared and set to be the length of the array. + A new declaration scope is created for the evaluation of the + AssignExpression..AssignExpression + and length appears in that scope only. +

+ + The first AssignExpression is taken to be the inclusive + lower bound + of the slice, and the second AssignExpression is the + exclusive upper bound. + The result of the expression is a slice of the PostfixExpression + array. + +

Primary Expressions

+ +

+
+

+	Identifier
+	.Identifier
+	this
+	super
+	null
+	true
+	false
+	NumericLiteral
+	CharacterLiteral
+	StringLiteral
+	FunctionLiteral
+	AssertExpression
+	BasicType . Identifier
+	typeid ( Type )
+	

+ +

.Identifier

+ + Identifier is looked up at module scope, rather than the current + lexically nested scope. + +

this

+ + Within a non-static member function, this resolves to + a reference to the object that called the function. + If a member function is called with an explicit reference + to typeof(this), a non-virtual call is made: + +

+
+

+	class A
+	{
+	    char get() { return 'A'; }
+
+	    char foo() { return typeof(this).get(); }
+	    char bar() { return this.get(); }
+	}
+
+	class B : A
+	{
+	    char get() { return 'B'; }
+	}
+
+	void main()
+	{
+	    B b = new B();
+
+	    b.foo();		// returns 'A'
+	    b.bar();		// returns 'B'
+	}
+	

+ + +

super

+ + Within a non-static member function, super resolves to + a reference to the object that called the function, cast to + its base class. It is an error if there is no base class. + super is not allowed in struct member + functions. + If a member function is called with an explicit reference + to super, a non-virtual call is made. + +

null

+ + The keyword null represents the null pointer value; + technically it is of type (void *). It + can be implicitly cast to any pointer type. + The integer 0 cannot be cast to the null pointer. + Nulls are also used for empty arrays. + +

true, false

+ + These are of type bit and resolve to values 1 and 0, + respectively. + +

Character Literals

+ + Character literals are single characters and resolve to one + of type char, wchar, or dchar. + If the literal is a \u escape sequence, it resolves to type wchar. + If the literal is a \U escape sequence, it resolves to type dchar. + Otherwise, it resolves to the type with the smallest size it + will fit into. + +

Function Literals

+ +

+
+

+	FunctionLiteral
+		function FunctionBody
+		function ( ParameterList ) FunctionBody
+		function Type ( ParameterList ) FunctionBody
+		delegate FunctionBody
+		delegate ( ParameterList ) FunctionBody
+		delegate Type ( ParameterList ) FunctionBody
+	

+ + FunctionLiterals enable embedding anonymous functions + and anonymous delegates directly into expressions. + Type is the return type of the function or delegate, + if omitted it defaults to void. + ( ParameterList ) forms the parameters to + the function. + If omitted it defaults to the empty parameter list (). + The type of a function literal is pointer to function or + pointer to delegate. +

+ + For example: + +

+
+

+	int function(char c) fp;	// declare pointer to a function
+
+	void test()
+	{
+	    static int foo(char c) { return 6; }
+
+	    fp = &foo;
+	}
+	

+ + is exactly equivalent to: + +

+
+

+	int function(char c) fp;
+
+	void test()
+	{
+	    fp = function int(char c) { return 6;} ;
+	}
+	

+ + And: + +

+
+

+	int abc(int delegate(long i));
+
+	void test()
+	{   int b = 3;
+	    int foo(long c) { return 6 + b; }
+
+	    abc(&foo);
+	}
+	

+ + is exactly equivalent to: + +

+
+

+	int abc(int delegate(long i));
+
+	void test()
+	{   int b = 3;
+
+	    abc( delegate int(long c) { return 6 + b; } );
+	}
+	

+ + Anonymous delegates can behave like arbitrary statement literals. + For example, here an arbitrary statement is executed by a loop: + +

+
+

+	double test()
+	{   double d = 7.6;
+	    float f = 2.3;
+
+	    void loop(int k, int j, void delegate() statement)
+	    {
+		for (int i = k; i < j; i++)
+		{
+		    statement();
+		}
+	    }
+
+	    loop(5, 100, delegate { d += 1; } );
+	    loop(3, 10,  delegate { f += 1; } );
+
+	    return d + f;
+	}
+	

+ + When comparing with nested + functions, the function form is analogous to static + or non-nested functions, and the delegate form is + analogous to non-static nested functions. In other words, + a delegate literal can access stack variables in its enclosing + function, a function literal cannot. + + +

Assert Expressions

+ +

+
+

+	AssertExpression:
+		assert ( Expression )
+	

+ + Asserts evaluate the expression. If the result is false, + an AssertError is thrown. If the result is true, then no + exception is thrown. + It is an error if the expression contains any side effects + that the program depends on. The compiler may optionally not + evaluate assert expressions at all. + The result type of an assert expression is void. + Asserts are a fundamental part of the + Contract Programming + support in D. +

+ + The expression assert(0) is a special case; it + signifies that it is unreachable code. + Either AssertError is thrown at runtime if it is reachable, + or a HLT instruction is executed. + The optimization and code generation phases of compilation may + assume that it is unreachable code. + +

Typeid Expressions

+ +

+
+

+	TypeidExpression:
+	    typeid ( Type )
+	

+ + Returns an instance of class TypeInfo corresponding + to Type. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/faq.html dmd-0.124/dmd/html/d/faq.html --- dmd-0.123/dmd/html/d/faq.html 2005-04-30 14:52:40.000000000 +0200 +++ dmd-0.124/dmd/html/d/faq.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,501 +1,531 @@ - - - - - -Digital Mars - The D Programming Language - FAQ - - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last modified Apr 30, 2005. -


- -

FAQ

- -The same questions keep cropping up, so the obvious thing to do is -prepare a FAQ. - - - -
-

Why the name D?

- -The original name was the Mars Programming Language. But my friends kept -calling it D, and I found myself starting to call it D. -The idea of D being a successor to C goes back at least as far as 1988, -as in this thread. - - -
-

Where can I get a D compiler?

- -Right here. - - -
-

Is there a linux port of D?

- -Yes, the D compiler includes a linux version. - - -
-

Is there a GNU version of D?

- - Yes, David Friedman has integrated the - D frontend with GCC. - -
-

How do I write my own D compiler for CPU X?

- - Burton Radons has written a - back end. - you can use as a guide. - - -
-

Where can I get a GUI for D?

- - DUI is a graphical user - interface based on the - GTK+ graphical toolkit. - - -
-

Where can I get an IDE for D?

- - LEDS is a D language - editor for Linux. - -
-

What about templates?

- - D now supports advanced templates. - -
-

Why emphasize implementation ease?

- -Isn't ease of use for the user of the language more important? Yes, it is. -But a vaporware language is useless to everyone. The easier a language -is to implement, the more robust implementations there will be. In C's -heyday, there were 30 different commericial C compilers for the IBM PC. -Not many made the transition to C++. In looking at -the C++ compilers on the market today, how many years of development went -into each? At least 10 years? Programmers waited years -for the various pieces of C++ to get implemented after they were specified. -If C++ was not so enormously popular, it's doubtful that very complex features -like multiple inheritance, templates, etc., would ever have been implemented. -

- -I suggest that if a language is easier to implement, then it is likely also -easier to understand. Isn't it better to spend time learning to write better -programs than language arcana? If a language can capture 90% of the power of -C++ with 10% of its complexity, I argue that is a worthwhile tradeoff. - - - -


-

Why is [expletive deleted] printf in D?

- -printf is not typesafe. It's old fashioned. It's not object-oriented. -It's not usable with user-defined types. printf is guilty as -charged. But it's just so darned useful. Nothing beats it for banging out -a quick dump of a value when debugging. -

- -Note: printf is actually not really -part of D anyway, but since D provides easy access to C's runtime library, -D gets it when needed. - - - -


-

Will D be open source?

- - The front end for D is open source, and the source comes with the - compiler. - There is a SourceForge - project underway to create a Gnu implementation of - D from this. - -
-

Why fall through on switch statements?

- -Many people have asked for a requirement that there be a break between -cases in a switch statement, that C's behavior of silently falling through -is the cause of many bugs. -

- -The reason D doesn't change this is for the same reason that integral -promotion rules and operator precedence rules were kept the same - to -make code that looks the same as in C operate the same. If it had subtly -different semantics, it will cause frustratingly subtle bugs. - -


-

Why should I use D instead of Java?

- - D is distinct from Java in purpose, philosophy and reality. - See this comparison. -

- - Java is designed to be write once, run everywhere. D is designed for writing - efficient native system apps. Although D and Java share the notion that - garbage collection is good and multiple inheritance is bad <g>, their - different design goals mean the languages have very different feels. - -


-

Doesn't C++ support strings, bit arrays, etc. with STL?

- - In the C++ standard library are mechanisms for doing strings, - bit arrays, dynamic arrays, associative arrays, bounds checked - arrays, and complex numbers. -

- - Sure, all this stuff can be done with libraries, - following certain coding disciplines, etc. But you can also do - object oriented programming in C (I've seen it done). - Isn't it incongruous that something like strings, - supported by the simplest BASIC interpreter, requires a very - large and complicated infrastructure to support? - Just the implementation of a string type in STL is over two - thousand lines of code, using every advanced feature of templates. - How much confidence can you have that this is all working - correctly, how do you fix it if it is not, what do you do with the - notoriously inscrutable error messages when there's an error - using it, how can you be sure you are using it correctly - (so there are no memory leaks, etc.)? -

- - D's implementation of strings is simple and straightforward. - There's little doubt how to use it, no worries about memory leaks, - error messages are to the point, and it isn't hard to see if it - is working as expected or not. - -


-

Can't garbage collection be done in C++ with an add-on library?

- - Yes, I use one myself. It isn't part of the language, though, and - requires some subverting of the language to make it work. - Using gc with C++ isn't for the standard or casual C++ programmer. - Building it into the - language, like in D, makes it practical for everyday programming chores. -

- - GC isn't that hard to implement, either, unless you're building one - of the more advanced ones. But a more advanced one is like building - a better optimizer - the language still works 100% correctly even - with a simple, basic one. The programming community is better served - by multiple implementations competing on quality of code generated - rather than by which corners of the spec are implemented at all. - -


-

Can't unit testing be done in C++ with an add-on library?

- - Sure. Try one out and then compare it with how D does it. - It'll be quickly obvious what an improvement building it into - the language is. - -
-

Why have an asm statement in a portable language?

- - An asm statement allows assembly code to be inserted directly into a D - function. Assembler code will obviously be inherently non-portable. D is - intended, however, to be a useful language for developing systems apps. - Systems apps almost invariably wind up with system dependent code in them - anyway, inline asm isn't much different. Inline asm will be useful for - things like accessing special CPU instructions, accessing flag bits, special - computational situations, and super optimizing a piece of code. -

- - Before the C compiler had an inline assembler, I used external assemblers. - There was constant grief because many, many different versions of the - assembler were out there, the vendors kept changing the syntax of the - assemblers, there were many different bugs in different versions, and even - the command line syntax kept changing. What it all meant was that users - could not reliably rebuild any code that needed assembler. An inline - assembler provided reliability and consistency. - -


-

Is there a GUI library for D?

- - Since D can call C functions, any GUI library with a C interface is - accessible from D. Various D GUI libraries and ports can be found at - AvailableGuiLibraries. - -
-

What is the point of 80 bit reals?

- - More precision enables more accurate floating point computations - to be done, especially when adding together large numbers of small - real numbers. Prof. Kahan, who designed the Intel floating point - unit, has an eloquent - paper - on the subject. - -
-

How do I do anonymous struct/unions in D?

- -
-struct Foo
-{
-    union { int a; int b; }
-    struct { int c; int d; }
-}
-
-void main()
-{
-    Foo f;
-
-    printf("Foo.size = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d\n",
-	f.size,
-	0,
-	&f.b - &f.a,
-	&f.c - &f.a,
-	&f.d - &f.a);
-}
-
- -
-

How do I get printf() to work with strings?

- - In C, the normal way to printf a string is to use the %s - format: -
-	char s[8];
-	strcpy(s, "foo");
-	printf("string = '%s'\n", s);
-	
- - Attempting this in D, as in: -
-	char[] s;
-	s = "foo";
-	printf("string = '%s'\n", s);
-	
- usually results in garbage being printed, or an access violation. - The cause is that in C, strings are terminated by a 0 character. - The %s format prints until a 0 is encountered. - In D, strings are not 0 terminated, the size is determined - by a separate length value. So, strings are printf'd using the - %.*s format: -
-	char[] s;
-	s = "foo";
-	printf("string = '%.*s'\n", s);
-	
- which will behave as expected. - Remember, though, that printf's %.*s will print until the length - is reached or a 0 is encountered, so D strings with embedded 0's - will only print up to the first 0. - -
-

Why are floating point values default initialized to nan rather than 0?

- - A floating point value, if no explicit initializer is given, - is initialized to nan (Not A Number): - -
-	double d;	// d is set to double.nan
-	
- - Nan's have the interesting property in that whenever a nan is - used as an operand in a computation, the result is a nan. Therefore, - nan's will propagate and appear in the output whenever a computation - made use of one. This implies that a nan appearing in the output - is an unambiguous indication of the use of an uninitialized - variable. -

- - If 0.0 was used as the default initializer for floating point - values, its effect can easily be unnoticed in the output, and so - if the default initializer was unintended, the bug may go - unrecognized. -

- - The default initializer value is not meant to be a useful value, - it is meant to expose bugs. Nan fills that role well. -

- - But surely the compiler can detect and issue an error message - for variables used that are not initialized? Most of the time, - it can, but not always, and what it can do is dependent on the - sophistication of the compiler's internal data flow analysis. - Hence, relying on such is unportable and unreliable. -

- - Because of the way CPUs are designed, there is no nan value for - integers, so D uses 0 instead. It doesn't have the advantages of - error detection that nan has, but at least errors resulting from - unintended default initializations will be consistent and therefore more - debuggable. - -


-

Why is overload the assignment operator not supported?

- - Most of the assignment operator overloading in C++ seems to be needed to - just keep track of who owns the memory. So by using reference types - coupled with GC, most of this just gets replaced with copying the - reference itself. For example, given an array of class objects, the - array's contents can be moved, sorted, shifted, etc., all without any - need for overloaded assignments. Ditto for function parameters and - return values. The references themselves just get moved about. There - just doesn't seem to be any need for copying the entire contents of one - class object into another pre-existing class object. -

- - Sometimes, one does need to create a copy of a class object, and for - that one can still write a copy constructor in D, but they just don't - seem to be needed remotely as much as in C++. -

- - Structs, being value objects, do get copied about. A copy is defined in - D to be a bit copy. I've never been comfortable with any object in C++ - that does something other than a bit copy when copied. Most of this - other behavior stems from that old problem of trying to manage memory. - Absent that, there doesn't seem to be a compelling rationale for - having anything other than a bit copy. - -


-

The '~' is not on my keyboard?

- - On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 - keys in sequence on the numeric pad. That will generate a '~' - character. - -
-

Can I link in C object files created with another compiler?

- - - DMD produces OMF (Microsoft Object Module Format) object - files while other compilers such as VC++ produce COFF object - files. - DMD's output is designed to work with DMC, the Digital Mars C - compiler, which also produces object files in OMF format. -

- - The OMF format that DMD uses is a Microsoft defined format based on an - earlier Intel designed one. Microsoft at one point decided to abandon it - in favor of a Microsoft defined variant on COFF. -

- - Using the same object format doesn't mean that any C library in that - format will successfully link and run. There is a lot more compatibility - required - such as calling conventions, name mangling, compiler helper - functions, and hidden assumptions about the way things work. If DMD - produced Microsoft COFF output files, there is still little chance that - they would work successfully with object files designed and tested for - use with VC. There were a lot of problems with this back when - Microsoft's compilers did generate OMF. -

- - Having a different object file format makes it helpful in identifying - library files that were not tested to work with DMD. If they are not, - weird problems would result even if they successfully managed to link - them together. It really takes an expert to get a binary built with a - compiler from one vendor to work with the output of another vendor's - compiler. -

- - That said, the linux version of DMD produces object files in the ELF - format which is standard on linux, and it is specifically designed to - work with the standard linux C compiler, gcc. -

- - There is one case where using existing C libraries does work - when - those libraries come in the form of a DLL conforming to the usual C ABI - interface. The linkable part of this is called an "import library", and - Microsoft COFF format import libraries can be successfully converted to - DMD OMF using the - coff2omf - tool. - - - - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved - -
- - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - FAQ + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

FAQ

+ +The same questions keep cropping up, so the obvious thing to do is +prepare a FAQ. + + + +
+

Why the name D?

+ +The original name was the Mars Programming Language. But my friends kept +calling it D, and I found myself starting to call it D. +The idea of D being a successor to C goes back at least as far as 1988, +as in this thread. + + +
+

Where can I get a D compiler?

+ +Right here. + + +
+

Is there a linux port of D?

+ +Yes, the D compiler includes a linux version. + + +
+

Is there a GNU version of D?

+ + Yes, David Friedman has integrated the + D frontend with GCC. + +
+

How do I write my own D compiler for CPU X?

+ + Burton Radons has written a + back end. + you can use as a guide. + + +
+

Where can I get a GUI for D?

+ + DUI is a graphical user + interface based on the + GTK+ graphical toolkit. + + +
+

Where can I get an IDE for D?

+ + LEDS is a D language + editor for Linux. + +
+

What about templates?

+ + D now supports advanced templates. + +
+

Why emphasize implementation ease?

+ +Isn't ease of use for the user of the language more important? Yes, it is. +But a vaporware language is useless to everyone. The easier a language +is to implement, the more robust implementations there will be. In C's +heyday, there were 30 different commericial C compilers for the IBM PC. +Not many made the transition to C++. In looking at +the C++ compilers on the market today, how many years of development went +into each? At least 10 years? Programmers waited years +for the various pieces of C++ to get implemented after they were specified. +If C++ was not so enormously popular, it's doubtful that very complex features +like multiple inheritance, templates, etc., would ever have been implemented. +

+ +I suggest that if a language is easier to implement, then it is likely also +easier to understand. Isn't it better to spend time learning to write better +programs than language arcana? If a language can capture 90% of the power of +C++ with 10% of its complexity, I argue that is a worthwhile tradeoff. + + + +


+

Why is [expletive deleted] printf in D?

+ +printf is not typesafe. It's old fashioned. It's not object-oriented. +It's not usable with user-defined types. printf is guilty as +charged. But it's just so darned useful. Nothing beats it for banging out +a quick dump of a value when debugging. +

+ +Note: printf is actually not really +part of D anyway, but since D provides easy access to C's runtime library, +D gets it when needed. + + + +


+

Will D be open source?

+ + The front end for D is open source, and the source comes with the + compiler. + There is a SourceForge + project underway to create a Gnu implementation of + D from this. + +
+

Why fall through on switch statements?

+ +Many people have asked for a requirement that there be a break between +cases in a switch statement, that C's behavior of silently falling through +is the cause of many bugs. +

+ +The reason D doesn't change this is for the same reason that integral +promotion rules and operator precedence rules were kept the same - to +make code that looks the same as in C operate the same. If it had subtly +different semantics, it will cause frustratingly subtle bugs. + +


+

Why should I use D instead of Java?

+ + D is distinct from Java in purpose, philosophy and reality. + See this comparison. +

+ + Java is designed to be write once, run everywhere. D is designed for writing + efficient native system apps. Although D and Java share the notion that + garbage collection is good and multiple inheritance is bad <g>, their + different design goals mean the languages have very different feels. + +


+

Doesn't C++ support strings, bit arrays, etc. with STL?

+ + In the C++ standard library are mechanisms for doing strings, + bit arrays, dynamic arrays, associative arrays, bounds checked + arrays, and complex numbers. +

+ + Sure, all this stuff can be done with libraries, + following certain coding disciplines, etc. But you can also do + object oriented programming in C (I've seen it done). + Isn't it incongruous that something like strings, + supported by the simplest BASIC interpreter, requires a very + large and complicated infrastructure to support? + Just the implementation of a string type in STL is over two + thousand lines of code, using every advanced feature of templates. + How much confidence can you have that this is all working + correctly, how do you fix it if it is not, what do you do with the + notoriously inscrutable error messages when there's an error + using it, how can you be sure you are using it correctly + (so there are no memory leaks, etc.)? +

+ + D's implementation of strings is simple and straightforward. + There's little doubt how to use it, no worries about memory leaks, + error messages are to the point, and it isn't hard to see if it + is working as expected or not. + +


+

Can't garbage collection be done in C++ with an add-on library?

+ + Yes, I use one myself. It isn't part of the language, though, and + requires some subverting of the language to make it work. + Using gc with C++ isn't for the standard or casual C++ programmer. + Building it into the + language, like in D, makes it practical for everyday programming chores. +

+ + GC isn't that hard to implement, either, unless you're building one + of the more advanced ones. But a more advanced one is like building + a better optimizer - the language still works 100% correctly even + with a simple, basic one. The programming community is better served + by multiple implementations competing on quality of code generated + rather than by which corners of the spec are implemented at all. + +


+

Can't unit testing be done in C++ with an add-on library?

+ + Sure. Try one out and then compare it with how D does it. + It'll be quickly obvious what an improvement building it into + the language is. + +
+

Why have an asm statement in a portable language?

+ + An asm statement allows assembly code to be inserted directly into a D + function. Assembler code will obviously be inherently non-portable. D is + intended, however, to be a useful language for developing systems apps. + Systems apps almost invariably wind up with system dependent code in them + anyway, inline asm isn't much different. Inline asm will be useful for + things like accessing special CPU instructions, accessing flag bits, special + computational situations, and super optimizing a piece of code. +

+ + Before the C compiler had an inline assembler, I used external assemblers. + There was constant grief because many, many different versions of the + assembler were out there, the vendors kept changing the syntax of the + assemblers, there were many different bugs in different versions, and even + the command line syntax kept changing. What it all meant was that users + could not reliably rebuild any code that needed assembler. An inline + assembler provided reliability and consistency. + +


+

Is there a GUI library for D?

+ + Since D can call C functions, any GUI library with a C interface is + accessible from D. Various D GUI libraries and ports can be found at + AvailableGuiLibraries. + +
+

What is the point of 80 bit reals?

+ + More precision enables more accurate floating point computations + to be done, especially when adding together large numbers of small + real numbers. Prof. Kahan, who designed the Intel floating point + unit, has an eloquent + paper + on the subject. + +
+

How do I do anonymous struct/unions in D?

+ +

+
+

+struct Foo
+{
+    union { int a; int b; }
+    struct { int c; int d; }
+}
+
+void main()
+{
+    Foo f;
+
+    printf("Foo.size = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d\n",
+	f.size,
+	0,
+	&f.b - &f.a,
+	&f.c - &f.a,
+	&f.d - &f.a);
+}
+

+ +


+

How do I get printf() to work with strings?

+ + In C, the normal way to printf a string is to use the %s + format: +

+
+

+	char s[8];
+	strcpy(s, "foo");
+	printf("string = '%s'\n", s);
+	

+ + Attempting this in D, as in: +

+
+

+	char[] s;
+	s = "foo";
+	printf("string = '%s'\n", s);
+	

+ usually results in garbage being printed, or an access violation. + The cause is that in C, strings are terminated by a 0 character. + The %s format prints until a 0 is encountered. + In D, strings are not 0 terminated, the size is determined + by a separate length value. So, strings are printf'd using the + %.*s format: +

+
+

+	char[] s;
+	s = "foo";
+	printf("string = '%.*s'\n", s);
+	

+ which will behave as expected. + Remember, though, that printf's %.*s will print until the length + is reached or a 0 is encountered, so D strings with embedded 0's + will only print up to the first 0. + +


+

Why are floating point values default initialized to nan rather than 0?

+ + A floating point value, if no explicit initializer is given, + is initialized to nan (Not A Number): + +

+
+

+	double d;	// d is set to double.nan
+	

+ + Nan's have the interesting property in that whenever a nan is + used as an operand in a computation, the result is a nan. Therefore, + nan's will propagate and appear in the output whenever a computation + made use of one. This implies that a nan appearing in the output + is an unambiguous indication of the use of an uninitialized + variable. +

+ + If 0.0 was used as the default initializer for floating point + values, its effect can easily be unnoticed in the output, and so + if the default initializer was unintended, the bug may go + unrecognized. +

+ + The default initializer value is not meant to be a useful value, + it is meant to expose bugs. Nan fills that role well. +

+ + But surely the compiler can detect and issue an error message + for variables used that are not initialized? Most of the time, + it can, but not always, and what it can do is dependent on the + sophistication of the compiler's internal data flow analysis. + Hence, relying on such is unportable and unreliable. +

+ + Because of the way CPUs are designed, there is no nan value for + integers, so D uses 0 instead. It doesn't have the advantages of + error detection that nan has, but at least errors resulting from + unintended default initializations will be consistent and therefore more + debuggable. + +


+

Why is overload the assignment operator not supported?

+ + Most of the assignment operator overloading in C++ seems to be needed to + just keep track of who owns the memory. So by using reference types + coupled with GC, most of this just gets replaced with copying the + reference itself. For example, given an array of class objects, the + array's contents can be moved, sorted, shifted, etc., all without any + need for overloaded assignments. Ditto for function parameters and + return values. The references themselves just get moved about. There + just doesn't seem to be any need for copying the entire contents of one + class object into another pre-existing class object. +

+ + Sometimes, one does need to create a copy of a class object, and for + that one can still write a copy constructor in D, but they just don't + seem to be needed remotely as much as in C++. +

+ + Structs, being value objects, do get copied about. A copy is defined in + D to be a bit copy. I've never been comfortable with any object in C++ + that does something other than a bit copy when copied. Most of this + other behavior stems from that old problem of trying to manage memory. + Absent that, there doesn't seem to be a compelling rationale for + having anything other than a bit copy. + +


+

The '~' is not on my keyboard?

+ + On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 + keys in sequence on the numeric pad. That will generate a '~' + character. + +
+

Can I link in C object files created with another compiler?

+ + + DMD produces OMF (Microsoft Object Module Format) object + files while other compilers such as VC++ produce COFF object + files. + DMD's output is designed to work with DMC, the Digital Mars C + compiler, which also produces object files in OMF format. +

+ + The OMF format that DMD uses is a Microsoft defined format based on an + earlier Intel designed one. Microsoft at one point decided to abandon it + in favor of a Microsoft defined variant on COFF. +

+ + Using the same object format doesn't mean that any C library in that + format will successfully link and run. There is a lot more compatibility + required - such as calling conventions, name mangling, compiler helper + functions, and hidden assumptions about the way things work. If DMD + produced Microsoft COFF output files, there is still little chance that + they would work successfully with object files designed and tested for + use with VC. There were a lot of problems with this back when + Microsoft's compilers did generate OMF. +

+ + Having a different object file format makes it helpful in identifying + library files that were not tested to work with DMD. If they are not, + weird problems would result even if they successfully managed to link + them together. It really takes an expert to get a binary built with a + compiler from one vendor to work with the output of another vendor's + compiler. +

+ + That said, the linux version of DMD produces object files in the ELF + format which is standard on linux, and it is specifically designed to + work with the standard linux C compiler, gcc. +

+ + There is one case where using existing C libraries does work - when + those libraries come in the form of a DLL conforming to the usual C ABI + interface. The linkable part of this is called an "import library", and + Microsoft COFF format import libraries can be successfully converted to + DMD OMF using the + coff2omf + tool. + + + + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/float.html dmd-0.124/dmd/html/d/float.html --- dmd-0.123/dmd/html/d/float.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/float.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,171 +1,198 @@ - - - - - -D Programming Language - Floating Point - - - -www.digitalmars.com -[Home] -[Search] -[D] - -
Last update Apr 21, 2004 -


- -

Floating Point

- -

Floating Point Intermediate Values

- - On many computers, greater - precision operations do not take any longer than lesser - precision operations, so it makes numerical sense to use - the greatest precision available for internal temporaries. - The philosophy is not to dumb down the language to the lowest - common hardware denominator, but to enable the exploitation - of the best capabilities of target hardware. -

- - For floating point operations and expression intermediate values, - a greater precision can be used than the type of the - expression. - Only the minimum precision is set by the types of the - operands, not the maximum. Implementation Note: On Intel - x86 machines, for example, - it is expected (but not required) that the intermediate - calculations be done to the full 80 bits of precision - implemented by the hardware. -

- - It's possible that, due to greater use of temporaries and - common subexpressions, optimized code may produce a more - accurate answer than unoptimized code. -

- - Algorithms should be written to work based on the minimum - precision of the calculation. They should not degrade or - fail if the actual precision is greater. Float or double types, - as opposed to the extended type, should only be used for: -

- -

Complex and Imaginary types

- - In existing languages, there is an astonishing amount of effort expended in trying to jam a - complex type onto existing type definition facilities: templates, structs, operator - overloading, etc., and it all usually ultimately fails. It fails because the semantics of - complex operations can be subtle, and it fails because the compiler doesn't know what the - programmer is trying to do, and so cannot optimize the semantic implementation. -

- - This is all done to avoid adding a new type. Adding a new type means that the compiler - can make all the semantics of complex work "right". The programmer then can rely on a - correct (or at least fixable ) implementation of complex. -

- - Coming with the baggage of a complex type is the need for an imaginary type. An - imaginary type eliminates some subtle semantic issues, and improves performance by not - having to perform extra operations on the implied 0 real part. -

- - Imaginary literals have an i suffix: - -

-	ireal j = 1.3i;
-	
- - There is no particular complex literal syntax, just add a real and imaginary type: - -
-	cdouble cd = 3.6 + 4i;
-	creal c = 4.5 + 2i;
-	
- - Complex numbers have two properties: - -
-	.re	get real part
-	.im	get imaginary part as a real
-	
- - For example: - -
-	cd.re		is 4.5 double
-	cd.im		is 2 double
-	c.re		is 4.5 real
-	c.im		is 2 real
-	
- -

Rounding Control

- - IEEE 754 floating point arithmetic includes the ability to set 4 different rounding modes. - D adds syntax to access them: [blah, blah, blah] [NOTE: this is perhaps better done with - a standard library call] - -

Exception Flags

- - IEEE 754 floating point arithmetic can set several flags based on what happened with a - computation: [blah, blah, blah]. These flags can be set/reset with the syntax: [blah, blah, - blah] [NOTE: this is perhaps better done with a standard library call] - -

Floating Point Comparisons

- - In addition to the usual < <= > >= == != comparison - operators, D adds more that are - specific to floating point. These are - !<>= - <> - <>= - !<= - !< - !>= - !> - !<> - and match the semantics for the - NCEG extensions to C. - -
-	Floating point comparison operators 
-
-	Operator	Relations	Invalid? 	Description
-
-			> < = ? 
-
-	<		F T F F		yes 	less than
-	>		T F F F		yes 	greater than
-	<=		F T T F		yes	less than or equal to
-	>=		T F T F		yes	greater than or equal to 
-	==		F F T F		no	equal to
-	!=		T T F T		no	unordered, less than, or greater than
-	!<>=		F F F T		no	unordered
-	<>		T T F F		yes	less than or greater than
-	<>=		T T T F		yes	less than, equal to, or greater than
-	!<=		T F F T		no	unordered or greater than
-	!<		T F T T		no	unordered, greater than, or equal to
-	!>=		F T F T		no	unordered or less than
-	!>		F T T T		no	unordered, less than, or equal to
-	!<>		F F T T		no	unordered or equal to
-	
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Floating Point + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Floating Point

+ +

Floating Point Intermediate Values

+ + On many computers, greater + precision operations do not take any longer than lesser + precision operations, so it makes numerical sense to use + the greatest precision available for internal temporaries. + The philosophy is not to dumb down the language to the lowest + common hardware denominator, but to enable the exploitation + of the best capabilities of target hardware. +

+ + For floating point operations and expression intermediate values, + a greater precision can be used than the type of the + expression. + Only the minimum precision is set by the types of the + operands, not the maximum. Implementation Note: On Intel + x86 machines, for example, + it is expected (but not required) that the intermediate + calculations be done to the full 80 bits of precision + implemented by the hardware. +

+ + It's possible that, due to greater use of temporaries and + common subexpressions, optimized code may produce a more + accurate answer than unoptimized code. +

+ + Algorithms should be written to work based on the minimum + precision of the calculation. They should not degrade or + fail if the actual precision is greater. Float or double types, + as opposed to the extended type, should only be used for: +

+ +

Complex and Imaginary types

+ + In existing languages, there is an astonishing amount of effort expended in trying to jam a + complex type onto existing type definition facilities: templates, structs, operator + overloading, etc., and it all usually ultimately fails. It fails because the semantics of + complex operations can be subtle, and it fails because the compiler doesn't know what the + programmer is trying to do, and so cannot optimize the semantic implementation. +

+ + This is all done to avoid adding a new type. Adding a new type means that the compiler + can make all the semantics of complex work "right". The programmer then can rely on a + correct (or at least fixable ) implementation of complex. +

+ + Coming with the baggage of a complex type is the need for an imaginary type. An + imaginary type eliminates some subtle semantic issues, and improves performance by not + having to perform extra operations on the implied 0 real part. +

+ + Imaginary literals have an i suffix: + +

+
+

+	ireal j = 1.3i;
+	

+ + There is no particular complex literal syntax, just add a real and imaginary type: + +

+
+

+	cdouble cd = 3.6 + 4i;
+	creal c = 4.5 + 2i;
+	

+ + Complex numbers have two properties: + +

+	.re	get real part
+	.im	get imaginary part as a real
+	
+ + For example: + +
+	cd.re		is 4.5 double
+	cd.im		is 2 double
+	c.re		is 4.5 real
+	c.im		is 2 real
+	
+ +

Rounding Control

+ + IEEE 754 floating point arithmetic includes the ability to set 4 different rounding modes. + D adds syntax to access them: [blah, blah, blah] [NOTE: this is perhaps better done with + a standard library call] + +

Exception Flags

+ + IEEE 754 floating point arithmetic can set several flags based on what happened with a + computation: [blah, blah, blah]. These flags can be set/reset with the syntax: [blah, blah, + blah] [NOTE: this is perhaps better done with a standard library call] + +

Floating Point Comparisons

+ + In addition to the usual < <= > >= == != comparison + operators, D adds more that are + specific to floating point. These are + !<>= + <> + <>= + !<= + !< + !>= + !> + !<> + and match the semantics for the + NCEG extensions to C. + +
+	Floating point comparison operators 
+
+	Operator	Relations	Invalid? 	Description
+
+			> < = ? 
+
+	<		F T F F		yes 	less than
+	>		T F F F		yes 	greater than
+	<=		F T T F		yes	less than or equal to
+	>=		T F T F		yes	greater than or equal to 
+	==		F F T F		no	equal to
+	!=		T T F T		no	unordered, less than, or greater than
+	!<>=		F F F T		no	unordered
+	<>		T T F F		yes	less than or greater than
+	<>=		T T T F		yes	less than, equal to, or greater than
+	!<=		T F F T		no	unordered or greater than
+	!<		T F T T		no	unordered, greater than, or equal to
+	!>=		F T F T		no	unordered or less than
+	!>		F T T T		no	unordered, less than, or equal to
+	!<>		F F T T		no	unordered or equal to
+	
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/function.html dmd-0.124/dmd/html/d/function.html --- dmd-0.123/dmd/html/d/function.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/function.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,758 +1,835 @@ - - - - - -D Programming Language - Functions - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Jun 23, 2004 -


- -

Functions

- -

Virtual Functions

- - All non-static non-private member functions are virtual. - This may sound - inefficient, but since the D compiler knows all of the class - hierarchy when generating code, all - functions that are not overridden can be optimized to be non-virtual. - In fact, since - C++ programmers tend to "when in doubt, make it virtual", the D way of - "make it - virtual unless we can prove it can be made non-virtual" results on - average much - more direct function calls. It also results in fewer bugs caused by - not declaring - a function virtual that gets overridden. -

- - Functions with non-D linkage cannot be virtual, and hence cannot be overridden. -

- - Functions marked as final may not be overridden in a - derived class, unless they are also private. - For example: - -

-	class A
-	{
-	    int def() { ... }
-	    final int foo() { ... }
-	    final private int bar() { ... }
-	    private int abc() { ... }
-	}
-
-	class B : A
-	{
-	    int def() { ... }	// ok, overrides A.def
-	    int foo() { ... }	// error, A.foo is final
-	    int bar() { ... }	// ok, A.bar is final private, but not virtual
-	    int abc() { ... }	// ok, A.abc is not virtual, B.abc is virtual
-	}
-
-	void test(A a)
-	{
-	    a.def();	// calls B.def
-	    a.foo();	// calls A.foo
-	    a.bar();	// calls A.bar
-	    a.abc();	// calls A.abc
-	}
-
-	void func()
-	{   B b = new B();
-	    test(b);
-	}
-	
- - Covariant return types - are supported, which means that the - overriding function in a derived class can return a type - that is derived from the type returned by the overridden function: - -
-	class A { }
-	class B : A { }
-
-	class Foo
-	{
-	    A test() { return null; }
-	}
-
-	class Bar : Foo
-	{
-	    B test() { return null; }	// overrides and is covariant with Foo.test()
-	}
-	
- -

Function Inheritance and Overriding

- - A functions in a derived class with the same name and parameter - types as a function in a base class overrides that function: - -
-	class A
-	{
-	    int foo(int x) { ... }
-	}
-
-	class B : A
-	{
-	    override int foo(int x) { ... }
-	}
-
-	void test()
-	{
-	    B b = new B();
-	    bar(b);
-	}
-
-	void bar(A a)
-	{
-	    a.foo();	// calls B.foo(int)
-	}
-	
- - However, when doing overload resolution, the functions in the base - class are not considered: - -
-	class A
-	{
-	    int foo(int x) { ... }
-	    int foo(long y) { ... }
-	}
-
-	class B : A
-	{
-	    override int foo(long x) { ... }
-	}
-
-	void test()
-	{
-	    B b = new B();
-	    bar(b);
-	}
-
-	void bar(A a)
-	{
-	    a.foo(1);		// calls A.foo(int)
-	    B b = new B();
-	    b.foo(1);		// calls B.foo(long), since A.foo(int) not considered
-	}
-	
- - To consider the base class's functions in the overload resolution - process, use an AliasDeclaration: - -
-	class A
-	{
-	    int foo(int x) { ... }
-	    int foo(long y) { ... }
-	}
-
-	class B : A
-	{
-	    alias A.foo foo;
-	    override int foo(long x) { ... }
-	}
-
-	void test()
-	{
-	    B b = new B();
-	    bar(b);
-	}
-
-	void bar(A a)
-	{
-	    a.foo(1);		// calls A.foo(int)
-	    B b = new B();
-	    b.foo(1);		// calls A.foo(int)
-	}
-	
- - A function parameter's default value is not inherited: - -
-	class A
-	{
-	    void foo(int x = 5) { ... }
-	}
-
-	class B : A
-	{
-	    void foo(int x = 7) { ... }
-	}
-
-	class C : B
-	{
-	    void foo(int x) { ... }
-	}
-
-
-	void test()
-	{
-	    A a = new A();
-	    a.foo();		// calls A.foo(5)
-
-	    B b = new B();
-	    b.foo();		// calls B.foo(7)
-
-	    C c = new C();
-	    c.foo();		// error, need an argument for C.foo
-	}
-	
- - -

Inline Functions

- - There is no inline keyword. The compiler makes the decision whether to - inline a function or not, analogously to the register keyword no - longer being relevant to a - compiler's decisions on enregistering variables. - (There is no register keyword either.) - - -

Function Overloading

- - In C++, there are many complex levels of function overloading, with - some defined as "better" matches than others. If the code designer - takes advantage of the more subtle - behaviors of overload function selection, the code can become - difficult to maintain. Not - only will it take a C++ expert to understand why one function is - selected over another, but different C++ compilers can implement - this tricky feature differently, producing - subtly disastrous results. -

- - In D, function overloading is simple. It matches exactly, it matches with - implicit conversions, or it does not match. If there is more than one match, it is an error. -

- - Functions defined with non-D linkage cannot be overloaded. - -

Function Parameters

- - Parameters are in, out, or inout. - in is the default; out and inout work like - storage classes. For example: - -
-	int foo(int x, out int y, inout int z, int q);
-	
- - x is in, y is out, z is inout, and q is in. -

- - out is rare enough, and inout even rarer, to - attach the keywords to - them and leave in as - the default. The reasons to have them are: - -

- - out parameters are set to the default initializer for the - type of it. For example: - -
-	void foo(out int bar)
-	{
-	}
-
-	int bar = 3;
-	foo(bar);
-	// bar is now 0
-	
- - -

Variadic Function Parameters

- - Functions can be variadic, meaning they can take an arbitrary - number of parameters. A variadic function is declared as taking - a parameter of ... after the required function parameters: - -
-	int foo(int x, int y, ...);
-
-	foo(3, 4);	// ok
-	foo(3, 4, 6.8);	// ok, one variadic argument
-	foo(2);		// error, y is a required argument
-	
- - Variadic functions with non-D linkage must have at least one - non-variadic parameter declared. - -
-	int abc(...);		// ok, D linkage
-	extern (C) def(...);	// error, must have at least one parameter
-	
- - Variadic functions have a special local variable declared for them, - _argptr, which is a void* pointer to the first of the - variadic - arguments. To access the arguments, _argptr must be cast - to a pointer to the expected argument type: - -
-	foo(3, 4, 5);	// first variadic argument is 5
-
-	int foo(int x, int y, ...)
-	{   int z;
-
-	    z = *cast(int*)_argptr;	// z is set to 5
-	}
-	
- - For variadic functions with D linkage, an additional hidden argument - with the name _arguments and type TypeInfo[] - is passed to the function. - _arguments gives the number of arguments and the type - of each, enabling the creation of typesafe variadic functions. - -
-	class FOO { }
-
-	void foo(int x, ...)
-	{
-	    printf("%d arguments\n", _arguments.length);
-	    for (int i = 0; i < _arguments.length; i++)
-	    {   _arguments[i].print();
-
-		if (_arguments[i] == typeid(int))
-		{
-		    int j = *cast(int *)_argptr;
-		    _argptr += int.sizeof;
-		    printf("\t%d\n", j);
-		}
-		else if (_arguments[i] == typeid(long))
-		{
-		    long j = *cast(long *)_argptr;
-		    _argptr += long.sizeof;
-		    printf("\t%lld\n", j);
-		}
-		else if (_arguments[i] == typeid(double))
-		{
-		    double d = *cast(double *)_argptr;
-		    _argptr += double.sizeof;
-		    printf("\t%g\n", d);
-		}
-		else if (_arguments[i] == typeid(FOO))
-		{
-		    FOO f = *cast(FOO*)_argptr;
-		    _argptr += FOO.sizeof;
-		    printf("\t%p\n", f);
-		}
-		else
-		    assert(0);
-	    }
-	}
-
-	void main()
-	{
-	    FOO f = new FOO();
-
-	    printf("%p\n", f);
-	    foo(1, 2, 3L, 4.5, f);
-	}
-	
- - which prints: - -
-	00870FD0
-	4 arguments
-	int
-		2
-	long
-		3
-	double
-		4.5
-	FOO
-		00870FD0
-	
- - To protect against the vagaries of stack layouts on different - CPU architectures, use std.stdarg to access the variadic - arguments: - -
-	import std.stdarg;
-
-	void foo(int x, ...)
-	{
-	    printf("%d arguments\n", _arguments.length);
-	    for (int i = 0; i < _arguments.length; i++)
-	    {   _arguments[i].print();
-
-		if (_arguments[i] == typeid(int))
-		{
-		    int j = va_arg!(int)(_argptr);
-		    printf("\t%d\n", j);
-		}
-		else if (_arguments[i] == typeid(long))
-		{
-		    long j = va_arg!(long)(_argptr);
-		    printf("\t%lld\n", j);
-		}
-		else if (_arguments[i] == typeid(double))
-		{
-		    double d = va_arg!(double)(_argptr);
-		    printf("\t%g\n", d);
-		}
-		else if (_arguments[i] == typeid(FOO))
-		{
-		    FOO f = va_arg!(FOO)(_argptr);
-		    printf("\t%p\n", f);
-		}
-		else
-		    assert(0);
-	    }
-	}
-	
- -

Local Variables

- - It is an error to use a local variable without first assigning it a - value. The implementation may not always be able to detect these - cases. Other language compilers sometimes issue a warning for this, - but since it is always a bug, it should be an error. -

- - It is an error to declare a local variable that is never referred to. - Dead variables, like anachronistic dead code, is just a source of - confusion for maintenance programmers. -

- - It is an error to declare a local variable that hides another local - variable in the same function: - -

-	void func(int x)
-	{   int x;		error, hides previous definition of x
-	     double y;
-	     ...
-	     {   char y;	error, hides previous definition of y
-	          int z;
-	     }
-	     {   wchar z;	legal, previous z is out of scope
-	     }
-	}
-	
- - While this might look unreasonable, in practice whenever - this is done it either is a - bug or at least looks like a bug. -

- - It is an error to return the address of or a reference to a - local variable. -

- - It is an error to have a local variable and a label with the same name. - -

Nested Functions

- - Functions may be nested within other functions: - -
-	int bar(int a)
-	{
-	    int foo(int b)
-	    {
-		int abc() { return 1; }
-
-		return b + abc();
-	    }
-	    return foo(a);
-	}
-
-	void test()
-	{
-	    int i = bar(3);	// i is assigned 4
-	}
-	
- - Nested functions can only be accessed by the most nested lexically - enclosing function, or by another nested function at the same - nesting depth: - -
-	int bar(int a)
-	{
-	    int foo(int b) { return b + 1; }
-	    int abc(int b) { return foo(b); }	// ok
-	    return foo(a);
-	}
-
-	void test()
-	{
-	    int i = bar(3);	// ok
-	    int j = bar.foo(3);	// error, bar.foo not visible
-	}
-	
- - Nested functions have access to the variables and other symbols - defined by the lexically enclosing function. - This access includes both the ability to read and write them. - -
-	int bar(int a)
-	{   int c = 3;
-
-	    int foo(int b)
-	    {
-		b += c;		// 4 is added to b
-		c++;		// bar.c is now 5
-		return b + c;	// 12 is returned
-	    }
-	    c = 4;
-	    int i = foo(a);	// i is set to 12
-	    return i + c;	// returns 17
-	}
-
-	void test()
-	{
-	    int i = bar(3);	// i is assigned 17
-	}
-	
- - This access can span multiple nesting levels: - -
-	int bar(int a)
-	{   int c = 3;
-
-	    int foo(int b)
-	    {
-		int abc()
-		{
-		    return c;	// access bar.c
-		}
-		return b + c + abc();
-	    }
-	    return foo(3);
-	}
-	
- - Static nested functions cannot access any stack variables of - any lexically enclosing function, but can access static variables. - This is analogous to how static member functions behave. - -
-	int bar(int a)
-	{   int c;
-	    static int d;
-
-	    static int foo(int b)
-	    {
-		b = d;		// ok
-		b = c;		// error, foo() cannot access frame of bar()
-		return b + 1;
-	    }
-	    return foo(a);
-	}
-	
- - Functions can be nested within member functions: - -
-	struct Foo
-	{   int a;
-
-	    int bar()
-	    {	int c;
-
-		int foo()
-		{
-		    return c + a;
-		}
-	    }
-	}
-	
- - Member functions of nested classes and structs do not have - access to the stack variables of the enclosing function, but - do have access to the other symbols: - -
-	void test()
-	{   int j;
-	    static int s;
-
-	    struct Foo
-	    {   int a;
-
-		int bar()
-		{   int c = s;		// ok, s is static
-		    int d = j;		// error, no access to frame of test()
-
-		    int foo()
-		    {
-			int e = s;	// ok, s is static
-			int f = j;	// error, no access to frame of test()
-			return c + a;	// ok, frame of bar() is accessible,
-					// so are members of Foo accessible via
-					// the 'this' pointer to Foo.bar()
-		    }
-		}
-	    }
-	}
-	
- - Nested functions always have the D function linkage type. -

- - Unlike module level declarations, declarations within function - scope are processed in order. This means that two nested functions - cannot mutually call each other: - -

-	void test()
-	{
-	    void foo() { bar(); }	// error, bar not defined
-	    void bar() { foo(); }	// ok
-	}
-	
- - The solution is to use a delegate: - -
-	void test()
-	{
-	    void delegate() fp;
-	    void foo() { fp(); }
-	    void bar() { foo(); }
-	    fp = &bar;
-	}
-	
- - Future directions: This restriction may be removed. - - -

Delegates, Function Pointers, and Dynamic Closures

- - A function pointer can point to a static nested function: - -
-	int function() fp;
-
-	void test()
-	{   static int a = 7;
-	    static int foo() { return a + 3; }
-
-	    fp = &foo;
-	}
-
-	void bar()
-	{
-	    test();
-	    int i = fp();	// i is set to 10
-	}
-	
- - A delegate can be set to a non-static nested function: - -
-	int delegate() dg;
-
-	void test()
-	{   int a = 7;
-	    int foo() { return a + 3; }
-
-	    dg = &foo;
-	    int i = dg();	// i is set to 10
-	}
-	
- - The stack variables, however, are not valid once the function - declaring them has exited, in the same manner that pointers to - stack variables are not valid upon exit from a function: - -
-	int* bar()
-	{   int b;
-	    test();
-	    int i = dg();	// error, test.a no longer exists
-	    return &b;		// error, bar.b not valid after bar() exits
-	}
-	
- - Delegates to non-static nested functions contain two pieces of - data: the pointer to the stack frame of the lexically enclosing - function (called the frame pointer) and the address of the - function. This is analogous to struct/class non-static member - function delegates consisting of a this pointer and - the address of the member function. - Both forms of delegates are interchangeable, and are actually - the same type: - -
-	struct Foo
-	{   int a = 7;
-	    int bar() { return a; }
-	}
-
-	int foo(int delegate() dg)
-	{
-	    return dg() + 1;
-	}
-
-	void test()
-	{
-	    int x = 27;
-	    int abc() { return x; }
-	    Foo f;
-	    int i;
-
-	    i = foo(&abc);	// i is set to 28
-	    i = foo(&f.bar);	// i is set to 8
-	}
-	
- - This combining of the environment and the function is called - a dynamic closure. -

- - Future directions: Function pointers and delegates may merge - into a common syntax and be interchangeable with each other. - -

Anonymous Functions and Anonymous Delegates

- - See Function Literals. - -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Functions + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

Functions

+ +

Virtual Functions

+ + All non-static non-private member functions are virtual. + This may sound + inefficient, but since the D compiler knows all of the class + hierarchy when generating code, all + functions that are not overridden can be optimized to be non-virtual. + In fact, since + C++ programmers tend to "when in doubt, make it virtual", the D way of + "make it + virtual unless we can prove it can be made non-virtual" results on + average much + more direct function calls. It also results in fewer bugs caused by + not declaring + a function virtual that gets overridden. +

+ + Functions with non-D linkage cannot be virtual, and hence cannot be overridden. +

+ + Functions marked as final may not be overridden in a + derived class, unless they are also private. + For example: + +

+
+

+	class A
+	{
+	    int def() { ... }
+	    final int foo() { ... }
+	    final private int bar() { ... }
+	    private int abc() { ... }
+	}
+
+	class B : A
+	{
+	    int def() { ... }	// ok, overrides A.def
+	    int foo() { ... }	// error, A.foo is final
+	    int bar() { ... }	// ok, A.bar is final private, but not virtual
+	    int abc() { ... }	// ok, A.abc is not virtual, B.abc is virtual
+	}
+
+	void test(A a)
+	{
+	    a.def();	// calls B.def
+	    a.foo();	// calls A.foo
+	    a.bar();	// calls A.bar
+	    a.abc();	// calls A.abc
+	}
+
+	void func()
+	{   B b = new B();
+	    test(b);
+	}
+	

+ + Covariant return types + are supported, which means that the + overriding function in a derived class can return a type + that is derived from the type returned by the overridden function: + +

+
+

+	class A { }
+	class B : A { }
+
+	class Foo
+	{
+	    A test() { return null; }
+	}
+
+	class Bar : Foo
+	{
+	    B test() { return null; }	// overrides and is covariant with Foo.test()
+	}
+	

+ +

Function Inheritance and Overriding

+ + A functions in a derived class with the same name and parameter + types as a function in a base class overrides that function: + +

+
+

+	class A
+	{
+	    int foo(int x) { ... }
+	}
+
+	class B : A
+	{
+	    override int foo(int x) { ... }
+	}
+
+	void test()
+	{
+	    B b = new B();
+	    bar(b);
+	}
+
+	void bar(A a)
+	{
+	    a.foo();	// calls B.foo(int)
+	}
+	

+ + However, when doing overload resolution, the functions in the base + class are not considered: + +

+
+

+	class A
+	{
+	    int foo(int x) { ... }
+	    int foo(long y) { ... }
+	}
+
+	class B : A
+	{
+	    override int foo(long x) { ... }
+	}
+
+	void test()
+	{
+	    B b = new B();
+	    bar(b);
+	}
+
+	void bar(A a)
+	{
+	    a.foo(1);		// calls A.foo(int)
+	    B b = new B();
+	    b.foo(1);		// calls B.foo(long), since A.foo(int) not considered
+	}
+	

+ + To consider the base class's functions in the overload resolution + process, use an AliasDeclaration: + +

+
+

+	class A
+	{
+	    int foo(int x) { ... }
+	    int foo(long y) { ... }
+	}
+
+	class B : A
+	{
+	    alias A.foo foo;
+	    override int foo(long x) { ... }
+	}
+
+	void test()
+	{
+	    B b = new B();
+	    bar(b);
+	}
+
+	void bar(A a)
+	{
+	    a.foo(1);		// calls A.foo(int)
+	    B b = new B();
+	    b.foo(1);		// calls A.foo(int)
+	}
+	

+ + A function parameter's default value is not inherited: + +

+
+

+	class A
+	{
+	    void foo(int x = 5) { ... }
+	}
+
+	class B : A
+	{
+	    void foo(int x = 7) { ... }
+	}
+
+	class C : B
+	{
+	    void foo(int x) { ... }
+	}
+
+
+	void test()
+	{
+	    A a = new A();
+	    a.foo();		// calls A.foo(5)
+
+	    B b = new B();
+	    b.foo();		// calls B.foo(7)
+
+	    C c = new C();
+	    c.foo();		// error, need an argument for C.foo
+	}
+	

+ + +

Inline Functions

+ + There is no inline keyword. The compiler makes the decision whether to + inline a function or not, analogously to the register keyword no + longer being relevant to a + compiler's decisions on enregistering variables. + (There is no register keyword either.) + + +

Function Overloading

+ + In C++, there are many complex levels of function overloading, with + some defined as "better" matches than others. If the code designer + takes advantage of the more subtle + behaviors of overload function selection, the code can become + difficult to maintain. Not + only will it take a C++ expert to understand why one function is + selected over another, but different C++ compilers can implement + this tricky feature differently, producing + subtly disastrous results. +

+ + In D, function overloading is simple. It matches exactly, it matches with + implicit conversions, or it does not match. If there is more than one match, it is an error. +

+ + Functions defined with non-D linkage cannot be overloaded. + +

Function Parameters

+ + Parameters are in, out, or inout. + in is the default; out and inout work like + storage classes. For example: + +

+
+

+	int foo(int x, out int y, inout int z, int q);
+	

+ + x is in, y is out, z is inout, and q is in. +

+ + out is rare enough, and inout even rarer, to + attach the keywords to + them and leave in as + the default. The reasons to have them are: + +

+ + out parameters are set to the default initializer for the + type of it. For example: + +

+
+

+	void foo(out int bar)
+	{
+	}
+
+	int bar = 3;
+	foo(bar);
+	// bar is now 0
+	

+ + +

Variadic Function Parameters

+ + Functions can be variadic, meaning they can take an arbitrary + number of parameters. A variadic function is declared as taking + a parameter of ... after the required function parameters: + +

+
+

+	int foo(int x, int y, ...);
+
+	foo(3, 4);	// ok
+	foo(3, 4, 6.8);	// ok, one variadic argument
+	foo(2);		// error, y is a required argument
+	

+ + Variadic functions with non-D linkage must have at least one + non-variadic parameter declared. + +

+
+

+	int abc(...);		// ok, D linkage
+	extern (C) def(...);	// error, must have at least one parameter
+	

+ + Variadic functions have a special local variable declared for them, + _argptr, which is a void* pointer to the first of the + variadic + arguments. To access the arguments, _argptr must be cast + to a pointer to the expected argument type: + +

+
+

+	foo(3, 4, 5);	// first variadic argument is 5
+
+	int foo(int x, int y, ...)
+	{   int z;
+
+	    z = *cast(int*)_argptr;	// z is set to 5
+	}
+	

+ + For variadic functions with D linkage, an additional hidden argument + with the name _arguments and type TypeInfo[] + is passed to the function. + _arguments gives the number of arguments and the type + of each, enabling the creation of typesafe variadic functions. + +

+
+

+	class FOO { }
+
+	void foo(int x, ...)
+	{
+	    printf("%d arguments\n", _arguments.length);
+	    for (int i = 0; i < _arguments.length; i++)
+	    {   _arguments[i].print();
+
+		if (_arguments[i] == typeid(int))
+		{
+		    int j = *cast(int *)_argptr;
+		    _argptr += int.sizeof;
+		    printf("\t%d\n", j);
+		}
+		else if (_arguments[i] == typeid(long))
+		{
+		    long j = *cast(long *)_argptr;
+		    _argptr += long.sizeof;
+		    printf("\t%lld\n", j);
+		}
+		else if (_arguments[i] == typeid(double))
+		{
+		    double d = *cast(double *)_argptr;
+		    _argptr += double.sizeof;
+		    printf("\t%g\n", d);
+		}
+		else if (_arguments[i] == typeid(FOO))
+		{
+		    FOO f = *cast(FOO*)_argptr;
+		    _argptr += FOO.sizeof;
+		    printf("\t%p\n", f);
+		}
+		else
+		    assert(0);
+	    }
+	}
+
+	void main()
+	{
+	    FOO f = new FOO();
+
+	    printf("%p\n", f);
+	    foo(1, 2, 3L, 4.5, f);
+	}
+	

+ + which prints: + +

+
+

+	00870FD0
+	4 arguments
+	int
+		2
+	long
+		3
+	double
+		4.5
+	FOO
+		00870FD0
+	

+ + To protect against the vagaries of stack layouts on different + CPU architectures, use std.stdarg to access the variadic + arguments: + +

+
+

+	import std.stdarg;
+
+	void foo(int x, ...)
+	{
+	    printf("%d arguments\n", _arguments.length);
+	    for (int i = 0; i < _arguments.length; i++)
+	    {   _arguments[i].print();
+
+		if (_arguments[i] == typeid(int))
+		{
+		    int j = va_arg!(int)(_argptr);
+		    printf("\t%d\n", j);
+		}
+		else if (_arguments[i] == typeid(long))
+		{
+		    long j = va_arg!(long)(_argptr);
+		    printf("\t%lld\n", j);
+		}
+		else if (_arguments[i] == typeid(double))
+		{
+		    double d = va_arg!(double)(_argptr);
+		    printf("\t%g\n", d);
+		}
+		else if (_arguments[i] == typeid(FOO))
+		{
+		    FOO f = va_arg!(FOO)(_argptr);
+		    printf("\t%p\n", f);
+		}
+		else
+		    assert(0);
+	    }
+	}
+	

+ +

Local Variables

+ + It is an error to use a local variable without first assigning it a + value. The implementation may not always be able to detect these + cases. Other language compilers sometimes issue a warning for this, + but since it is always a bug, it should be an error. +

+ + It is an error to declare a local variable that is never referred to. + Dead variables, like anachronistic dead code, is just a source of + confusion for maintenance programmers. +

+ + It is an error to declare a local variable that hides another local + variable in the same function: + +

+
+

+	void func(int x)
+	{   int x;		error, hides previous definition of x
+	     double y;
+	     ...
+	     {   char y;	error, hides previous definition of y
+	          int z;
+	     }
+	     {   wchar z;	legal, previous z is out of scope
+	     }
+	}
+	

+ + While this might look unreasonable, in practice whenever + this is done it either is a + bug or at least looks like a bug. +

+ + It is an error to return the address of or a reference to a + local variable. +

+ + It is an error to have a local variable and a label with the same name. + +

Nested Functions

+ + Functions may be nested within other functions: + +

+
+

+	int bar(int a)
+	{
+	    int foo(int b)
+	    {
+		int abc() { return 1; }
+
+		return b + abc();
+	    }
+	    return foo(a);
+	}
+
+	void test()
+	{
+	    int i = bar(3);	// i is assigned 4
+	}
+	

+ + Nested functions can only be accessed by the most nested lexically + enclosing function, or by another nested function at the same + nesting depth: + +

+
+

+	int bar(int a)
+	{
+	    int foo(int b) { return b + 1; }
+	    int abc(int b) { return foo(b); }	// ok
+	    return foo(a);
+	}
+
+	void test()
+	{
+	    int i = bar(3);	// ok
+	    int j = bar.foo(3);	// error, bar.foo not visible
+	}
+	

+ + Nested functions have access to the variables and other symbols + defined by the lexically enclosing function. + This access includes both the ability to read and write them. + +

+
+

+	int bar(int a)
+	{   int c = 3;
+
+	    int foo(int b)
+	    {
+		b += c;		// 4 is added to b
+		c++;		// bar.c is now 5
+		return b + c;	// 12 is returned
+	    }
+	    c = 4;
+	    int i = foo(a);	// i is set to 12
+	    return i + c;	// returns 17
+	}
+
+	void test()
+	{
+	    int i = bar(3);	// i is assigned 17
+	}
+	

+ + This access can span multiple nesting levels: + +

+
+

+	int bar(int a)
+	{   int c = 3;
+
+	    int foo(int b)
+	    {
+		int abc()
+		{
+		    return c;	// access bar.c
+		}
+		return b + c + abc();
+	    }
+	    return foo(3);
+	}
+	

+ + Static nested functions cannot access any stack variables of + any lexically enclosing function, but can access static variables. + This is analogous to how static member functions behave. + +

+
+

+	int bar(int a)
+	{   int c;
+	    static int d;
+
+	    static int foo(int b)
+	    {
+		b = d;		// ok
+		b = c;		// error, foo() cannot access frame of bar()
+		return b + 1;
+	    }
+	    return foo(a);
+	}
+	

+ + Functions can be nested within member functions: + +

+
+

+	struct Foo
+	{   int a;
+
+	    int bar()
+	    {	int c;
+
+		int foo()
+		{
+		    return c + a;
+		}
+	    }
+	}
+	

+ + Member functions of nested classes and structs do not have + access to the stack variables of the enclosing function, but + do have access to the other symbols: + +

+
+

+	void test()
+	{   int j;
+	    static int s;
+
+	    struct Foo
+	    {   int a;
+
+		int bar()
+		{   int c = s;		// ok, s is static
+		    int d = j;		// error, no access to frame of test()
+
+		    int foo()
+		    {
+			int e = s;	// ok, s is static
+			int f = j;	// error, no access to frame of test()
+			return c + a;	// ok, frame of bar() is accessible,
+					// so are members of Foo accessible via
+					// the 'this' pointer to Foo.bar()
+		    }
+		}
+	    }
+	}
+	

+ + Nested functions always have the D function linkage type. +

+ + Unlike module level declarations, declarations within function + scope are processed in order. This means that two nested functions + cannot mutually call each other: + +

+
+

+	void test()
+	{
+	    void foo() { bar(); }	// error, bar not defined
+	    void bar() { foo(); }	// ok
+	}
+	

+ + The solution is to use a delegate: + +

+
+

+	void test()
+	{
+	    void delegate() fp;
+	    void foo() { fp(); }
+	    void bar() { foo(); }
+	    fp = &bar;
+	}
+	

+ + Future directions: This restriction may be removed. + + +

Delegates, Function Pointers, and Dynamic Closures

+ + A function pointer can point to a static nested function: + +

+
+

+	int function() fp;
+
+	void test()
+	{   static int a = 7;
+	    static int foo() { return a + 3; }
+
+	    fp = &foo;
+	}
+
+	void bar()
+	{
+	    test();
+	    int i = fp();	// i is set to 10
+	}
+	

+ + A delegate can be set to a non-static nested function: + +

+
+

+	int delegate() dg;
+
+	void test()
+	{   int a = 7;
+	    int foo() { return a + 3; }
+
+	    dg = &foo;
+	    int i = dg();	// i is set to 10
+	}
+	

+ + The stack variables, however, are not valid once the function + declaring them has exited, in the same manner that pointers to + stack variables are not valid upon exit from a function: + +

+
+

+	int* bar()
+	{   int b;
+	    test();
+	    int i = dg();	// error, test.a no longer exists
+	    return &b;		// error, bar.b not valid after bar() exits
+	}
+	

+ + Delegates to non-static nested functions contain two pieces of + data: the pointer to the stack frame of the lexically enclosing + function (called the frame pointer) and the address of the + function. This is analogous to struct/class non-static member + function delegates consisting of a this pointer and + the address of the member function. + Both forms of delegates are interchangeable, and are actually + the same type: + +

+
+

+	struct Foo
+	{   int a = 7;
+	    int bar() { return a; }
+	}
+
+	int foo(int delegate() dg)
+	{
+	    return dg() + 1;
+	}
+
+	void test()
+	{
+	    int x = 27;
+	    int abc() { return x; }
+	    Foo f;
+	    int i;
+
+	    i = foo(&abc);	// i is set to 28
+	    i = foo(&f.bar);	// i is set to 8
+	}
+	

+ + This combining of the environment and the function is called + a dynamic closure. +

+ + Future directions: Function pointers and delegates may merge + into a common syntax and be interchangeable with each other. + +

Anonymous Functions and Anonymous Delegates

+ + See Function Literals. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/future.html dmd-0.124/dmd/html/d/future.html --- dmd-0.123/dmd/html/d/future.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/future.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,44 +1,68 @@ - - - - - -D Programming Language - Future Directions - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last modified Jan 14, 2004. -


- -

Future Directions

- - The following new features for D are planned, but the details have - not been worked out: - -
    -
  1. Mixins. -
  2. Template inheritance. -
  3. Array literal expressions. -
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Future Directions + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Future Directions

+ + The following new features for D are planned, but the details have + not been worked out: + +
    +
  1. Implicit function template instantiation. +
  2. Template inheritance. +
  3. Array literal expressions. +
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/garbage.html dmd-0.124/dmd/html/d/garbage.html --- dmd-0.123/dmd/html/d/garbage.html 2005-04-29 12:19:24.000000000 +0200 +++ dmd-0.124/dmd/html/d/garbage.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,325 +1,363 @@ - - - - - -D Programming Language - Garbage Collection - - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update Apr 29, 2005 -


- -

Garbage Collection

- - D is a fully garbage collected language. That means that it is never necessary - to free memory. Just allocate as needed, and the garbage collector will - periodically return all unused memory to the pool of available memory. -

- - C and C++ programmers accustomed to explicitly managing memory - allocation and - deallocation will likely be skeptical of the benefits and efficacy of - garbage collection. Experience both with new projects written with - garbage collection in mind, and converting existing projects to garbage - collection shows that: - -

- - Garbage collection is not a panacea. There are some downsides: - - - - These constraints are addressed by techniques outlined - in Memory Management. - -

How Garbage Collection Works

- - To be written... - -

Interfacing Garbage Collected Objects With Foreign Code

- - The garbage collector looks for roots in its static data segment, and the - stacks and register contents of each thread. If the only root of an object - is held outside of this, then the collecter will miss it and free the - memory. -

- - To avoid this from happening, - -

- -

Pointers and the Garbage Collector

- - Pointers in D can be broadly divided into two categories: those that - point to garbage collected memory, and those that do not. Examples - of the latter are pointers created by calls to C's malloc(), pointers - received from C library routines, pointers to static data, - pointers to objects on the stack, etc. For those pointers, anything - that is legal in C can be done with them. -

- - For garbage collected pointers and references, however, there are some - restrictions. These restrictions are minor, but they are intended - to enable the maximum flexibility in garbage collector design. -

- - Undefined behavior: -

- - Things that are reliable and can be done: - - - - One can avoid using pointers anyway for most tasks. D provides features - rendering most explicit pointer uses obsolete, such as reference - objects, - dynamic arrays, and garbage collection. Pointers - are provided in order to interface successfully with C API's and for - some low level work. - -

Working with the Garbage Collector

- - Garbage collection doesn't solve every memory deallocation problem. For - example, if a root to a large data structure is kept, the garbage - collector cannot reclaim it, even if it is never referred to again. To - eliminate this problem, it is good practice to set a reference or - pointer to an object to null when no longer needed. -

- - This advice applies only to static references or references embedded - inside other objects. There is not much point for such stored on the - stack to be nulled, since the collector doesn't scan for roots past the - top of the stack, and because new stack frames are initialized anyway. - -

References

- - - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved

- - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Garbage Collection + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Garbage Collection

+ + D is a fully garbage collected language. That means that it is never necessary + to free memory. Just allocate as needed, and the garbage collector will + periodically return all unused memory to the pool of available memory. +

+ + C and C++ programmers accustomed to explicitly managing memory + allocation and + deallocation will likely be skeptical of the benefits and efficacy of + garbage collection. Experience both with new projects written with + garbage collection in mind, and converting existing projects to garbage + collection shows that: + +

+ + Garbage collection is not a panacea. There are some downsides: + + + + These constraints are addressed by techniques outlined + in Memory Management. + +

How Garbage Collection Works

+ + To be written... + +

Interfacing Garbage Collected Objects With Foreign Code

+ + The garbage collector looks for roots in its static data segment, and the + stacks and register contents of each thread. If the only root of an object + is held outside of this, then the collecter will miss it and free the + memory. +

+ + To avoid this from happening, + +

+ +

Pointers and the Garbage Collector

+ + Pointers in D can be broadly divided into two categories: those that + point to garbage collected memory, and those that do not. Examples + of the latter are pointers created by calls to C's malloc(), pointers + received from C library routines, pointers to static data, + pointers to objects on the stack, etc. For those pointers, anything + that is legal in C can be done with them. +

+ + For garbage collected pointers and references, however, there are some + restrictions. These restrictions are minor, but they are intended + to enable the maximum flexibility in garbage collector design. +

+ + Undefined behavior: +

+ + Things that are reliable and can be done: + + + + One can avoid using pointers anyway for most tasks. D provides features + rendering most explicit pointer uses obsolete, such as reference + objects, + dynamic arrays, and garbage collection. Pointers + are provided in order to interface successfully with C API's and for + some low level work. + +

Working with the Garbage Collector

+ + Garbage collection doesn't solve every memory deallocation problem. For + example, if a root to a large data structure is kept, the garbage + collector cannot reclaim it, even if it is never referred to again. To + eliminate this problem, it is good practice to set a reference or + pointer to an object to null when no longer needed. +

+ + This advice applies only to static references or references embedded + inside other objects. There is not much point for such stored on the + stack to be nulled, since the collector doesn't scan for roots past the + top of the stack, and because new stack frames are initialized anyway. + +

References

+ + + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/html.html dmd-0.124/dmd/html/d/html.html --- dmd-0.123/dmd/html/d/html.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/html.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,68 +1,107 @@ - - -Embedding D in HTML - - - -www.digitalmars.com -[Home] -[Search] -[D] -


- -

Embedding D in HTML

- - The D compiler is designed to be able to extract and compile D code - embedded within HTML files. This capability means that D code can - be written to be displayed within a browser utilizing the full formatting - and display capability of HTML. -

- For example, it is possible to make all uses of a class name actually be - hyperlinks to where the class is defined. There's nothing new to learn for - the person browsing the code, he just uses the normal features of an - HTML browser. Strings can be displayed in green, - comments in red, and - keywords in boldface, for one possibility. It is even possible - to embed pictures in the code, as normal HTML image tags. -

- Embedding D in HTML makes it possible to put the documentation for code and - the code itself all together in one file. It is no longer necessary to - relegate documentation in comments, to be extracted later by a tech writer. - The code and the documentation for it can be maintained simultaneously, - with no duplication of effort. -

- How it works is straightforward. If the source file to the compiler ends in - .htm or .html, the code is assumed to be embedded in HTML. The source is then - preprocessed by stripping all text outside of <code> and </code> tags. - Then, all other HTML tags are stripped, and embedded character encodings are - converted to ASCII. All newlines in the original HTML remain in their - corresponding positions in the preprocessed text, so the debug line numbers - remain consistent. The resulting text is then fed to the D compiler. -

- Here's an example of the D program "hello world" embedded in - this very HTML file. This file can be compiled and run. - -
-
- import std.c.stdio;
-
- int main()
- {
-  printf("hello world\n");
-  return 0;
- }
-
-
- -

Feedback and Comments

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

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Embedding D in HTML + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Embedding D in HTML

+ + The D compiler is designed to be able to extract and compile D code + embedded within HTML files. This capability means that D code can + be written to be displayed within a browser utilizing the full formatting + and display capability of HTML. +

+ For example, it is possible to make all uses of a class name actually be + hyperlinks to where the class is defined. There's nothing new to learn for + the person browsing the code, he just uses the normal features of an + HTML browser. Strings can be displayed in green, + comments in red, and + keywords in boldface, for one possibility. It is even possible + to embed pictures in the code, as normal HTML image tags. +

+ Embedding D in HTML makes it possible to put the documentation for code and + the code itself all together in one file. It is no longer necessary to + relegate documentation in comments, to be extracted later by a tech writer. + The code and the documentation for it can be maintained simultaneously, + with no duplication of effort. +

+ How it works is straightforward. If the source file to the compiler ends + in .htm or .html, the code is assumed to be embedded in HTML. The source + is then preprocessed by stripping all text outside of <code> and + </code> tags. Then, all other HTML tags are stripped, and embedded + character encodings are converted to ASCII. + The processing does not attempt to diagnose errors in the HTML itself. + All newlines in the original + HTML remain in their corresponding positions in the preprocessed text, + so the debug line numbers remain consistent. The resulting text is then + fed to the D compiler. +

+ Here's an example of the D program "hello world" embedded in + this very HTML file. This file can be compiled and run. + +

+
+

+
+    import std.c.stdio;
+
+    int main()
+    {
+	 printf("hello world\n");
+	 return 0;
+    }
+
+

+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + + diff -uNr dmd-0.123/dmd/html/d/htomodule.html dmd-0.124/dmd/html/d/htomodule.html --- dmd-0.123/dmd/html/d/htomodule.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/htomodule.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,430 +1,515 @@ - - -D Programming Language - Converting C .h Files to D Modules - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Feb 10, 2005 -


- -

Converting C .h Files to D Modules

- - While D cannot directly compile C source code, it can easily - interface to C code, be linked with C object files, and call - C functions in DLLs. - The interface to C code is normally found in C .h files. - So, the trick to connecting with C code is in converting C - .h files to D modules. - This turns out to be difficult to do mechanically since - inevitably some human judgement must be applied. - This is a guide to doing such conversions. - -

Preprocessor

- - .h files can sometimes be a bewildering morass of layers of - macros, #include files, #ifdef's, etc. D doesn't - include a text preprocessor like the C preprocessor, - so the first step is to remove the need for - it by taking the preprocessed output. For DMC (the Digital - Mars C/C++ compiler), the command: - -
-	dmc -c program.h -e -l
-	
- - will create a file program.lst which is the source file after - all text preprocessing. -

- - Remove all the #if, #ifdef, #include, - etc. statements. - -

Linkage

- - Generally, surround the entire module with: - -
-	extern (C)
-	{
-	     ...file contents...
-	}
-	
- - to give it C linkage. - -

Types

- - A little global search and replace will take care of renaming - the C types to D types. The following table shows a typical mapping - for 32 bit C code: - - - - - - - - - - - - - - -
C type - D type -
long double - real -
unsigned long long - ulong -
long long - long -
unsigned long - uint -
long - int -
unsigned - uint -
unsigned short - ushort -
signed char - byte -
unsigned char - ubyte -
wchar_t - wchar or dchar -
bool - int -
- -

NULL

- - NULL and ((void*)0) should be replaced - with null. - -

Numeric Literals

- - Any 'L' or 'l' numeric literal suffixes should be removed, - as a C long is (usually) the same size as a D int. - Similarly, 'LL' suffixes should be replaced with a - single 'L'. - Any 'u' suffix will work the same in D. - -

String Literals

- - In most cases, any 'L' prefix to a string can just be dropped, - as D will implicitly convert strings to wide characters if - necessary. However, one can also replace: - -
-	L"string"
-	
- - with: - -
-	cast(wchar[])"string"
-	
- -

Macros

- - Lists of macros like: - -
-	#define FOO	1
-	#define BAR	2
-	#define ABC	3
-	#define DEF	40
-	
- - can be replaced with: - -
-	enum
-	{   FOO = 1,
-	    BAR = 2,
-	    ABC = 3,
-	    DEF = 40
-	}
-	
- - or with: - -
-	const int FOO = 1;
-	const int BAR = 2;
-	const int ABC = 3;
-	const int DEF = 40;
-	
- - Function style macros, such as: - -
-	#define MAX(a,b) ((a) < (b) ? (b) : (a))
-	
- - can be replaced with functions: - -
-	int MAX(int a, int b) { return (a < b) ? b : a); }
-	
- -

Declaration Lists

- - D doesn't allow declaration lists to change the type. - Hence: - -
-	int *p, q, t[3], *s;
-	
- - should be written as: - -
-	int* p, s;
-	int q;
-	int[3] t;
-	
- -

Void Parameter Lists

- - Functions that take no parameters: - -
-	int foo(void);
-	
- - are in D: - -
-	int foo();
-	
- -

Const Type Modifiers

- - D has const as a storage class, not a type modifier. Hence, just - drop any const used as a type modifier: - -
-	void foo(const int *p, char *const q);
-	
- - becomes: - -
-	void foo(int* p, char* q);
-	
- -

Extern Global C Variables

- - Whenever a global variable is declared in D, it is also defined. - But if it's also defined by the C object file being linked in, - there will be a multiple definition error. To fix this problem, - the idea is to declare the variable in a D module, but not link - in that module. For example, given a C header file named - foo.h: - - -
-	struct Foo { };
-	struct Foo bar;
-	
-
- - It can be replaced with two D modules, foo.d: - -
-	struct Foo { }
-	import fooextern;
-	
- - and fooextern.d: - -
-	Foo bar;
-	
- - The foo.obj file is linked in, and fooextern.obj - is not. While this is not the most elegant looking method, it does - work, and since it is pretty rare in C libraries to use global - variables in its interface, it isn't an issue in practice. - -

Typedef

- - alias is the D equivalent to the C typedef: - -
-	typedef int foo;
-	
- - becomes: - -
-	alias int foo;
-	
- -

Structs

- - Replace declarations like: - -
-	typedef struct Foo
-	{   int a;
-	    int b;
-	} Foo, *pFoo, *lpFoo;
-	
- - with: - -
-	struct Foo
-	{   int a;
-	    int b;
-	}
-	alias Foo* pFoo, lpFoo;
-	
- -

Struct Member Alignment

- - A good D implementation by default will align struct members the - same way as the C compiler it was designed to work with. But - if the .h file has some #pragma's to control alignment, they - can be duplicated with the D align attribute: - -
-	#pragma pack(1)
-	struct Foo
-	{
-	    int a;
-	    int b;
-	};
-	#pragma pack()
-	
- - becomes: - -
-	struct Foo
-	{
-	  align (1):
-	    int a;
-	    int b;
-	}
-	
- -

Nested Structs

- -
-	struct Foo
-	{
-	    int a;
-	    struct Bar
-	    {
-		int c;
-	    } bar;
-	};
-
-	struct Abc
-	{
-	    int a;
-	    struct
-	    {
-		int c;
-	    } bar;
-	};
-	
- - becomes: - -
-	struct Foo
-	{
-	    int a;
-	    struct Bar
-	    {
-		int c;
-	    }
-	    Bar bar;
-	};
-
-	struct Abc
-	{
-	    int a;
-	    struct
-	    {
-		int c;
-	    }
-	};
-	
- -

__cdecl, __pascal, __stdcall

- -
-	int __cdecl x;
-	int __cdecl foo(int a);
-	int __pascal bar(int b);
-	int __stdcall abc(int c);
-	
- - become: - -
-	extern (C) int x;
-	extern (C) int foo(int a);
-	extern (Pascal) int bar(int b);
-	extern (Windows) int abc(int c);
-	
- -

__declspec(dllimport)

- -
-	__declspec(dllimport) int __stdcall foo(int a);
-	
- - becomes: - -
-	export extern (Windows) int foo(int a);
-	
- -

__fastcall

- - Unfortunately, D doesn't support the __fastcall convention. - Therefore, a shim will be needed, either written in C: - - -
-	int __fastcall foo(int a);
-
-	int myfoo(int a)
-	{
-	    return foo(int a);
-	}
-	
-
- - and compiled with a C compiler that supports __fastcall and - linked in, or compile the above, disassemble it with - obj2asm - and insert it in a D myfoo shim with - inline assembler. - -

Feedback and Comments

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

- - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Converting C .h Files to D Modules + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

Converting C .h Files to D Modules

+ + While D cannot directly compile C source code, it can easily + interface to C code, be linked with C object files, and call + C functions in DLLs. + The interface to C code is normally found in C .h files. + So, the trick to connecting with C code is in converting C + .h files to D modules. + This turns out to be difficult to do mechanically since + inevitably some human judgement must be applied. + This is a guide to doing such conversions. + +

Preprocessor

+ + .h files can sometimes be a bewildering morass of layers of + macros, #include files, #ifdef's, etc. D doesn't + include a text preprocessor like the C preprocessor, + so the first step is to remove the need for + it by taking the preprocessed output. For DMC (the Digital + Mars C/C++ compiler), the command: + +
+	dmc -c program.h -e -l
+	
+ + will create a file program.lst which is the source file after + all text preprocessing. +

+ + Remove all the #if, #ifdef, #include, + etc. statements. + +

Linkage

+ + Generally, surround the entire module with: + +

+
+

+	extern (C)
+	{
+	     ...file contents...
+	}
+	

+ + to give it C linkage. + +

Types

+ + A little global search and replace will take care of renaming + the C types to D types. The following table shows a typical mapping + for 32 bit C code: + + + + + + + + + + + + + + +
C type + D type +
long double + real +
unsigned long long + ulong +
long long + long +
unsigned long + uint +
long + int +
unsigned + uint +
unsigned short + ushort +
signed char + byte +
unsigned char + ubyte +
wchar_t + wchar or dchar +
bool + int +
+ +

NULL

+ + NULL and ((void*)0) should be replaced + with null. + +

Numeric Literals

+ + Any 'L' or 'l' numeric literal suffixes should be removed, + as a C long is (usually) the same size as a D int. + Similarly, 'LL' suffixes should be replaced with a + single 'L'. + Any 'u' suffix will work the same in D. + +

String Literals

+ + In most cases, any 'L' prefix to a string can just be dropped, + as D will implicitly convert strings to wide characters if + necessary. However, one can also replace: + +

+
+

+	L"string"
+	

+ + with: + +

+
+

+	cast(wchar[])"string"
+	

+ +

Macros

+ + Lists of macros like: + +

+
+

+	#define FOO	1
+	#define BAR	2
+	#define ABC	3
+	#define DEF	40
+	

+ + can be replaced with: + +

+
+

+	enum
+	{   FOO = 1,
+	    BAR = 2,
+	    ABC = 3,
+	    DEF = 40
+	}
+	

+ + or with: + +

+
+

+	const int FOO = 1;
+	const int BAR = 2;
+	const int ABC = 3;
+	const int DEF = 40;
+	

+ + Function style macros, such as: + +

+
+

+	#define MAX(a,b) ((a) < (b) ? (b) : (a))
+	

+ + can be replaced with functions: + +

+
+

+	int MAX(int a, int b) { return (a < b) ? b : a); }
+	

+ +

Declaration Lists

+ + D doesn't allow declaration lists to change the type. + Hence: + +

+
+

+	int *p, q, t[3], *s;
+	

+ + should be written as: + +

+
+

+	int* p, s;
+	int q;
+	int[3] t;
+	

+ +

Void Parameter Lists

+ + Functions that take no parameters: + +

+
+

+	int foo(void);
+	

+ + are in D: + +

+
+

+	int foo();
+	

+ +

Const Type Modifiers

+ + D has const as a storage class, not a type modifier. Hence, just + drop any const used as a type modifier: + +

+
+

+	void foo(const int *p, char *const q);
+	

+ + becomes: + +

+
+

+	void foo(int* p, char* q);
+	

+ +

Extern Global C Variables

+ + Whenever a global variable is declared in D, it is also defined. + But if it's also defined by the C object file being linked in, + there will be a multiple definition error. To fix this problem, + the idea is to declare the variable in a D module, but not link + in that module. For example, given a C header file named + foo.h: + +

+
+

+	struct Foo { };
+	struct Foo bar;
+	

+ + It can be replaced with two D modules, foo.d: + +

+
+

+	struct Foo { }
+	import fooextern;
+	

+ + and fooextern.d: + +

+
+

+	Foo bar;
+	

+ + The foo.obj file is linked in, and fooextern.obj + is not. While this is not the most elegant looking method, it does + work, and since it is pretty rare in C libraries to use global + variables in its interface, it isn't an issue in practice. + +

Typedef

+ + alias is the D equivalent to the C typedef: + +

+
+

+	typedef int foo;
+	

+ + becomes: + +

+
+

+	alias int foo;
+	

+ +

Structs

+ + Replace declarations like: + +

+
+

+	typedef struct Foo
+	{   int a;
+	    int b;
+	} Foo, *pFoo, *lpFoo;
+	

+ + with: + +

+
+

+	struct Foo
+	{   int a;
+	    int b;
+	}
+	alias Foo* pFoo, lpFoo;
+	

+ +

Struct Member Alignment

+ + A good D implementation by default will align struct members the + same way as the C compiler it was designed to work with. But + if the .h file has some #pragma's to control alignment, they + can be duplicated with the D align attribute: + +

+
+

+	#pragma pack(1)
+	struct Foo
+	{
+	    int a;
+	    int b;
+	};
+	#pragma pack()
+	

+ + becomes: + +

+
+

+	struct Foo
+	{
+	  align (1):
+	    int a;
+	    int b;
+	}
+	

+ +

Nested Structs

+ +

+
+

+	struct Foo
+	{
+	    int a;
+	    struct Bar
+	    {
+		int c;
+	    } bar;
+	};
+
+	struct Abc
+	{
+	    int a;
+	    struct
+	    {
+		int c;
+	    } bar;
+	};
+	

+ + becomes: + +

+
+

+	struct Foo
+	{
+	    int a;
+	    struct Bar
+	    {
+		int c;
+	    }
+	    Bar bar;
+	};
+
+	struct Abc
+	{
+	    int a;
+	    struct
+	    {
+		int c;
+	    }
+	};
+	

+ +

__cdecl, __pascal, __stdcall

+ +

+
+

+	int __cdecl x;
+	int __cdecl foo(int a);
+	int __pascal bar(int b);
+	int __stdcall abc(int c);
+	

+ + becomes: + +

+
+

+	extern (C) int x;
+	extern (C) int foo(int a);
+	extern (Pascal) int bar(int b);
+	extern (Windows) int abc(int c);
+	

+ +

__declspec(dllimport)

+ +

+
+

+	__declspec(dllimport) int __stdcall foo(int a);
+	

+ + becomes: + +

+
+

+	export extern (Windows) int foo(int a);
+	

+ +

__fastcall

+ + Unfortunately, D doesn't support the __fastcall convention. + Therefore, a shim will be needed, either written in C: + +

+
+

+	int __fastcall foo(int a);
+
+	int myfoo(int a)
+	{
+	    return foo(int a);
+	}
+	

+ + and compiled with a C compiler that supports __fastcall and + linked in, or compile the above, disassemble it with + obj2asm + and insert it in a D myfoo shim with + inline assembler. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/iasm.html dmd-0.124/dmd/html/d/iasm.html --- dmd-0.123/dmd/html/d/iasm.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/iasm.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,1089 +1,1113 @@ - - - -Digital Mars - D Inline Assembler - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Apr 2, 2005 -


- -

D x86 Inline Assembler

- - - Some Assembly Required - - - D, being a systems programming language, provides an inline assembler. - The inline assembler is standardized for D implementations across - the same CPU family, for example, the Intel Pentium inline assembler - for a Win32 D compiler will be syntax compatible with the inline - assembler for Linux running on an Intel Pentium. -

- - Differing D implementations, however, are free to innovate upon - the memory model, function call/return conventions, argument - passing conventions, etc. -

- - This document describes the x86 implementation of the inline assembler. - -

-	AsmInstruction:
-		Identifier : AsmInstruction
-		align IntegerExpression
-		even
-		naked
-		db Operands
-		ds Operands
-		di Operands
-		dl Operands
-		df Operands
-		dd Operands
-		de Operands
-		Opcode
-		Opcode Operands
-
-	Operands
-		Operand
-		Operand , Operands
-	
- -

Labels

- - Assembler instructions can be labeled just like other statements. - They can be the target of goto statements. - For example: - -
-	void *pc;
-	asm
-	{
-	    call L1		;
-	 L1:			;
-	    pop	EBX		;
-	    mov	pc[EBP],EBX	;	// pc now points to code at L1
-	}
-	
- -

align IntegerExpression

- - Causes the assembler to emit NOP instructions to align the next - assembler instruction on an IntegerExpression boundary. - IntegerExpression must evaluate to an integer that is - a power of 2. -

- - Aligning the start of a loop body can sometimes have a dramatic - effect on the execution speed. - -

even

- - Causes the assembler to emit NOP instructions to align the next - assembler instruction on an even boundary. - -

naked

- - Causes the compiler to not generate the function prolog and epilog - sequences. This means such is the responsibility of inline - assembly programmer, and is normally used when the entire function - is to be written in assembler. - -

db, ds, di, dl, df, dd, de

- - These pseudo ops are for inserting raw data directly into - the code. - db is for bytes, - ds is for 16 bit words, - di is for 32 bit words, - dl is for 64 bit words, - df is for 32 bit floats, - dd is for 64 bit doubles, - and de is for 80 bit extended reals. - Each can have multiple operands. - If an operand is a string literal, it is as if there were length - operands, where length is the number of characters in the string. - One character is used per operand. - For example: - -
-	asm
-	{
-	    db 5,6,0x83;   // insert bytes 0x05, 0x06, and 0x83 into code
-	    ds 0x1234;     // insert bytes 0x34, 0x12
-	    di 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00
-	    dl 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	    df 1.234;      // insert float 1.234
-	    dd 1.234;      // insert double 1.234
-	    de 1.234;      // insert extended 1.234
-	    db "abc";      // insert bytes 0x61, 0x62, and 0x63
-	    ds "abc";      // insert bytes 0x61, 0x00, 0x62, 0x00, 0x63, 0x00
-	}
-	
- -

Opcodes

- - A list of supported opcodes is at the end. -

- - The following registers are supported. Register names - are always in upper case. - -

-
AL, AH, AX, EAX -
BL, BH, BX, EBX -
CL, CH, CX, ECX -
DL, DH, DX, EDX -
BP, EBP -
SP, ESP -
DI, EDI -
SI, ESI -
ES, CS, SS, DS, GS, FS -
CR0, CR2, CR3, CR4 -
DR0, DR1, DR2, DR3, DR6, DR7 -
TR3, TR4, TR5, TR6, TR7 -
ST -
ST(0), ST(1), ST(2), ST(3), - ST(4), ST(5), ST(6), ST(7) -
MM0, MM1, MM2, MM3, - MM4, MM5, MM6, MM7 -
- -

Special Cases

- -
- -
lock, rep, repe, repne, - repnz, repz -
These prefix instructions do not appear in the same statement - as the instructions they prefix; they appear in their own statement. - For example: -
-	asm
-	{
-	    rep   ;
-	    movsb ;
-	}
-	
- -
pause -
This opcode is not supported by the assembler, instead use -
-	{
-	    rep  ;
-	    nop  ;
-	}
-	
- which produces the same result. - -
floating point ops -
Use the two operand form of the instruction format; -
-	fdiv ST(1);	// wrong
-	fmul ST;        // wrong
-	fdiv ST,ST(1);	// right
-	fmul ST,ST(0);	// right
-	
- -
- -

Operands

- -
-	Operand:
-	    AsmExp
-
-	AsmExp:
-	    AsmLogOrExp
-	    AsmLogOrExp ? AsmExp : AsmExp
-
-	AsmLogOrExp:
-	    AsmLogAndExp
-	    AsmLogAndExp || AsmLogAndExp
-
-	AsmLogAndExp:
-	    AsmOrExp
-	    AsmOrExp && AsmOrExp
-
-	AsmOrExp:
-	    AsmXorExp
-	    AsmXorExp | AsmXorExp
-
-	AsmXorExp:
-	    AsmAndExp
-	    AsmAndExp ^ AsmAndExp
-
-	AsmAndExp:
-	    AsmEqualExp
-	    AsmEqualExp & AsmEqualExp
-
-	AsmEqualExp:
-	    AsmRelExp
-	    AsmRelExp == AsmRelExp
-	    AsmRelExp != AsmRelExp
-
-	AsmRelExp:
-	    AsmShiftExp
-	    AsmShiftExp < AsmShiftExp
-	    AsmShiftExp <= AsmShiftExp
-	    AsmShiftExp > AsmShiftExp
-	    AsmShiftExp >= AsmShiftExp
-
-	AsmShiftExp:
-	    AsmAddExp
-	    AsmAddExp << AsmAddExp
-	    AsmAddExp >> AsmAddExp
-	    AsmAddExp >>> AsmAddExp
-
-	AsmAddExp:
-	    AsmMulExp
-	    AsmMulExp + AsmMulExp
-	    AsmMulExp - AsmMulExp
-
-	AsmMulExp:
-	    AsmBrExp
-	    AsmBrExp * AsmBrExp
-	    AsmBrExp / AsmBrExp
-	    AsmBrExp % AsmBrExp
-
-	AsmBrExp:
-	    AsmUnaExp
-	    AsmBrExp [ AsmExp ]
-
-	AsmUnaExp:
-	    AsmTypePrefix AsmExp
-	    offset AsmExp
-	    seg AsmExp
-	    + AsmUnaExp
-	    - AsmUnaExp
-	    ! AsmUnaExp
-	    ~ AsmUnaExp
-	    AsmPrimaryExp
-
-	AsmPrimaryExp
-	    IntegerConstant
-	    FloatConstant
-	    __LOCAL_SIZE
-	    $
-	    Register
-	    DotIdentifier
-
-	DotIdentifier
-	    Identifier
-	    Identifier . DotIdentifier
-	
- The operand syntax more or less follows the Intel CPU documentation - conventions. - In particular, the convention is that for two operand instructions - the source is the right operand and the destination is the left - operand. - The syntax differs from that of Intel's in order to be compatible - with the D language tokenizer and to simplify parsing. - -

Operand Types

- -
-	AsmTypePrefix:
-		near ptr
-		far ptr
-		byte ptr
-		short ptr
-		int ptr
-		word ptr
-		dword ptr
-		float ptr
-		double ptr
-		extended ptr
-	
- - In cases where the operand size is ambiguous, as in: - -
-	add	[EAX],3		;
-	
- - it can be disambiguated by using an AsmTypePrefix: - -
-	add	byte ptr [EAX],3	;
-	add	int ptr [EAX],7		;
-	
- -

Struct/Union/Class Member Offsets

- - To access members of an aggregate, given a pointer to the aggregate - is in a register, use the qualified name of the member: - -
-	struct Foo { int a,b,c; }
-	int bar(Foo *f)
-	{
-	    asm
-	    {	mov	EBX,f		;
-		mov	EAX,Foo.b[EBX]	;
-	    }
-	}
-	
- -

Special Symbols

- -
- -
$ -
Represents the program counter of the start of the next - instruction. So, - -
-	jmp	$  ;
- - branches to the instruction following the jmp instruction. -

- -

__LOCAL_SIZE -
This gets replaced by the number of local bytes in the local - stack frame. It is most handy when the naked is invoked - and a custom stack frame is programmed. - -
- -

Opcodes Supported

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
aaaaadaamaasadc
addaddpdaddpsaddsdaddss
andandnpdandnpsandpdandps
arplboundbsfbsrbswap
btbtcbtrbtscall
cbwcdqclccldclflush
clicltscmccmovacmovae
cmovbcmovbecmovccmovecmovg
cmovgecmovlcmovlecmovnacmovnae
cmovnbcmovnbecmovnccmovnecmovng
cmovngecmovnlcmovnlecmovnocmovnp
cmovnscmovnzcmovocmovpcmovpe
cmovpocmovscmovzcmpcmppd
cmppscmpscmpsbcmpsdcmpss
cmpswcmpxch8bcmpxchgcomisdcomiss
cpuidcvtdq2pdcvtdq2pscvtpd2dqcvtpd2pi
cvtpd2pscvtpi2pdcvtpi2pscvtps2dqcvtps2pd
cvtps2picvtsd2sicvtsd2sscvtsi2sdcvtsi2ss
cvtss2sdcvtss2sicvttpd2dqcvttpd2picvttps2dq
cvttps2picvttsd2sicvttss2sicwdcwde
dadaadasdbdd
dedecdfdidiv
divpddivpsdivsddivssdl
dqdsdtdwemms
enterf2xm1fabsfaddfaddp
fbldfbstpfchsfclexfcmovb
fcmovbefcmovefcmovnbfcmovnbefcmovne
fcmovnufcmovufcomfcomifcomip
fcompfcomppfcosfdecstpfdisi
fdivfdivpfdivrfdivrpfeni
ffreefiaddficomficompfidiv
fidivrfildfimulfincstpfinit
fistfistpfisubfisubrfld
fld1fldcwfldenvfldl2efldl2t
fldlg2fldln2fldpifldzfmul
fmulpfnclexfndisifnenifninit
fnopfnsavefnstcwfnstenvfnstsw
fpatanfpremfprem1fptanfrndint
frstorfsavefscalefsetpmfsin
fsincosfsqrtfstfstcwfstenv
fstpfstswfsubfsubpfsubr
fsubrpftstfucomfucomifucomip
fucompfucomppfwaitfxamfxch
fxrstorfxsavefxtractfyl2xfyl2xp1
hltidivimulininc
insinsbinsdinswint
intoinvdinvlpgiretiretd
jajaejbjbejc
jcxzjejecxzjgjge
jljlejmpjnajnae
jnbjnbejncjnejng
jngejnljnlejnojnp
jnsjnzjojpjpe
jpojsjzlahflar
ldmxcsrldslealeaveles
lfencelfslgdtlgslidt
lldtlmswlocklodslodsb
lodsdlodswlooploopeloopne
loopnzloopzlsllssltr
maskmovdqumaskmovqmaxpdmaxpsmaxsd
maxssmfenceminpdminpsminsd
minssmovmovapdmovapsmovd
movdq2qmovdqamovdqumovhlpsmovhpd
movhpsmovlhpsmovlpdmovlpsmovmskpd
movmskpsmovntdqmovntimovntpdmovntps
movntqmovqmovq2dqmovsmovsb
movsdmovssmovswmovsxmovupd
movupsmovzxmulmulpdmulps
mulsdmulssnegnopnot
ororpdorpsoutouts
outsboutsdoutswpackssdwpacksswb
packuswbpaddbpadddpaddqpaddsb
paddswpaddusbpadduswpaddwpand
pandnpavgbpavgwpcmpeqbpcmpeqd
pcmpeqwpcmpgtbpcmpgtdpcmpgtwpextrw
pinsrwpmaddwdpmaxswpmaxubpminsw
pminubpmovmskbpmulhuwpmulhwpmullw
pmuludqpoppopapopadpopf
popfdporprefetchntaprefetcht0prefetcht1
prefetcht2psadbwpshufdpshufhwpshuflw
pshufwpslldpslldqpsllqpsllw
psradpsrawpsrldpsrldqpsrlq
psrlwpsubbpsubdpsubqpsubsb
psubswpsubusbpsubuswpsubwpunpckhbw
punpckhdqpunpckhqdqpunpckhwdpunpcklbwpunpckldq
punpcklqdqpunpcklwdpushpushapushad
pushfpushfdpxorrclrcpps
rcpssrcrrdmsrrdpmcrdtsc
repreperepnerepnzrepz
retretfrolrorrsm
rsqrtpsrsqrtsssahfsalsar
sbbscasscasbscasdscasw
setasetaesetbsetbesetc
setesetgsetgesetlsetle
setnasetnaesetnbsetnbesetnc
setnesetngsetngesetnlsetnle
setnosetnpsetnssetnzseto
setpsetpesetposetssetz
sfencesgdtshlshldshr
shrdshufpdshufpssidtsldt
smswsqrtpdsqrtpssqrtsdsqrtss
stcstdstistmxcsrstos
stosbstosdstoswstrsub
subpdsubpssubsdsubsssysenter
sysexittestucomisducomissud2
unpckhpdunpckhpsunpcklpdunpcklpsverr
verwwaitwbinvdwrmsrxadd
xchgxlatxlatbxorxorpd
xorps
- -

Pentium 4 (Prescott) Opcodes Supported

- - - - - - - - - - - - - - - - - - - - - - -
addsubpdaddsubpsfisttphaddpdhaddps
hsubpdhsubpslddqumonitormovddup
movshdupmovsldupmwait
- -

AMD Opcodes Supported

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pavgusbpf2idpfaccpfaddpfcmpeq
pfcmpgepfcmpgtpfmaxpfminpfmul
pfnaccpfpnaccpfrcppfrcpit1pfrcpit2
pfrsqit1pfrsqrtpfsubpfsubrpi2fd
pmulhrwpswapd
- -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved

- - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Inline Assembler + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ + +

D x86 Inline Assembler

+ + + Some Assembly Required + + + D, being a systems programming language, provides an inline assembler. + The inline assembler is standardized for D implementations across + the same CPU family, for example, the Intel Pentium inline assembler + for a Win32 D compiler will be syntax compatible with the inline + assembler for Linux running on an Intel Pentium. +

+ + Differing D implementations, however, are free to innovate upon + the memory model, function call/return conventions, argument + passing conventions, etc. +

+ + This document describes the x86 implementation of the inline assembler. + +

+	AsmInstruction:
+		Identifier : AsmInstruction
+		align IntegerExpression
+		even
+		naked
+		db Operands
+		ds Operands
+		di Operands
+		dl Operands
+		df Operands
+		dd Operands
+		de Operands
+		Opcode
+		Opcode Operands
+
+	Operands
+		Operand
+		Operand , Operands
+	
+ +

Labels

+ + Assembler instructions can be labeled just like other statements. + They can be the target of goto statements. + For example: + +
+	void *pc;
+	asm
+	{
+	    call L1		;
+	 L1:			;
+	    pop	EBX		;
+	    mov	pc[EBP],EBX	;	// pc now points to code at L1
+	}
+	
+ +

align IntegerExpression

+ + Causes the assembler to emit NOP instructions to align the next + assembler instruction on an IntegerExpression boundary. + IntegerExpression must evaluate to an integer that is + a power of 2. +

+ + Aligning the start of a loop body can sometimes have a dramatic + effect on the execution speed. + +

even

+ + Causes the assembler to emit NOP instructions to align the next + assembler instruction on an even boundary. + +

naked

+ + Causes the compiler to not generate the function prolog and epilog + sequences. This means such is the responsibility of inline + assembly programmer, and is normally used when the entire function + is to be written in assembler. + +

db, ds, di, dl, df, dd, de

+ + These pseudo ops are for inserting raw data directly into + the code. + db is for bytes, + ds is for 16 bit words, + di is for 32 bit words, + dl is for 64 bit words, + df is for 32 bit floats, + dd is for 64 bit doubles, + and de is for 80 bit extended reals. + Each can have multiple operands. + If an operand is a string literal, it is as if there were length + operands, where length is the number of characters in the string. + One character is used per operand. + For example: + +
+	asm
+	{
+	    db 5,6,0x83;   // insert bytes 0x05, 0x06, and 0x83 into code
+	    ds 0x1234;     // insert bytes 0x34, 0x12
+	    di 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00
+	    dl 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	    df 1.234;      // insert float 1.234
+	    dd 1.234;      // insert double 1.234
+	    de 1.234;      // insert extended 1.234
+	    db "abc";      // insert bytes 0x61, 0x62, and 0x63
+	    ds "abc";      // insert bytes 0x61, 0x00, 0x62, 0x00, 0x63, 0x00
+	}
+	
+ +

Opcodes

+ + A list of supported opcodes is at the end. +

+ + The following registers are supported. Register names + are always in upper case. + +

+
AL, AH, AX, EAX +
BL, BH, BX, EBX +
CL, CH, CX, ECX +
DL, DH, DX, EDX +
BP, EBP +
SP, ESP +
DI, EDI +
SI, ESI +
ES, CS, SS, DS, GS, FS +
CR0, CR2, CR3, CR4 +
DR0, DR1, DR2, DR3, DR6, DR7 +
TR3, TR4, TR5, TR6, TR7 +
ST +
ST(0), ST(1), ST(2), ST(3), + ST(4), ST(5), ST(6), ST(7) +
MM0, MM1, MM2, MM3, + MM4, MM5, MM6, MM7 +
+ +

Special Cases

+ +
+ +
lock, rep, repe, repne, + repnz, repz +
These prefix instructions do not appear in the same statement + as the instructions they prefix; they appear in their own statement. + For example: +
+	asm
+	{
+	    rep   ;
+	    movsb ;
+	}
+	
+ +
pause +
This opcode is not supported by the assembler, instead use +
+	{
+	    rep  ;
+	    nop  ;
+	}
+	
+ which produces the same result. + +
floating point ops +
Use the two operand form of the instruction format; +
+	fdiv ST(1);	// wrong
+	fmul ST;        // wrong
+	fdiv ST,ST(1);	// right
+	fmul ST,ST(0);	// right
+	
+ +
+ +

Operands

+ +
+	Operand:
+	    AsmExp
+
+	AsmExp:
+	    AsmLogOrExp
+	    AsmLogOrExp ? AsmExp : AsmExp
+
+	AsmLogOrExp:
+	    AsmLogAndExp
+	    AsmLogAndExp || AsmLogAndExp
+
+	AsmLogAndExp:
+	    AsmOrExp
+	    AsmOrExp && AsmOrExp
+
+	AsmOrExp:
+	    AsmXorExp
+	    AsmXorExp | AsmXorExp
+
+	AsmXorExp:
+	    AsmAndExp
+	    AsmAndExp ^ AsmAndExp
+
+	AsmAndExp:
+	    AsmEqualExp
+	    AsmEqualExp & AsmEqualExp
+
+	AsmEqualExp:
+	    AsmRelExp
+	    AsmRelExp == AsmRelExp
+	    AsmRelExp != AsmRelExp
+
+	AsmRelExp:
+	    AsmShiftExp
+	    AsmShiftExp < AsmShiftExp
+	    AsmShiftExp <= AsmShiftExp
+	    AsmShiftExp > AsmShiftExp
+	    AsmShiftExp >= AsmShiftExp
+
+	AsmShiftExp:
+	    AsmAddExp
+	    AsmAddExp << AsmAddExp
+	    AsmAddExp >> AsmAddExp
+	    AsmAddExp >>> AsmAddExp
+
+	AsmAddExp:
+	    AsmMulExp
+	    AsmMulExp + AsmMulExp
+	    AsmMulExp - AsmMulExp
+
+	AsmMulExp:
+	    AsmBrExp
+	    AsmBrExp * AsmBrExp
+	    AsmBrExp / AsmBrExp
+	    AsmBrExp % AsmBrExp
+
+	AsmBrExp:
+	    AsmUnaExp
+	    AsmBrExp [ AsmExp ]
+
+	AsmUnaExp:
+	    AsmTypePrefix AsmExp
+	    offset AsmExp
+	    seg AsmExp
+	    + AsmUnaExp
+	    - AsmUnaExp
+	    ! AsmUnaExp
+	    ~ AsmUnaExp
+	    AsmPrimaryExp
+
+	AsmPrimaryExp
+	    IntegerConstant
+	    FloatConstant
+	    __LOCAL_SIZE
+	    $
+	    Register
+	    DotIdentifier
+
+	DotIdentifier
+	    Identifier
+	    Identifier . DotIdentifier
+	
+ The operand syntax more or less follows the Intel CPU documentation + conventions. + In particular, the convention is that for two operand instructions + the source is the right operand and the destination is the left + operand. + The syntax differs from that of Intel's in order to be compatible + with the D language tokenizer and to simplify parsing. + +

Operand Types

+ +
+	AsmTypePrefix:
+		near ptr
+		far ptr
+		byte ptr
+		short ptr
+		int ptr
+		word ptr
+		dword ptr
+		float ptr
+		double ptr
+		extended ptr
+	
+ + In cases where the operand size is ambiguous, as in: + +
+	add	[EAX],3		;
+	
+ + it can be disambiguated by using an AsmTypePrefix: + +
+	add	byte ptr [EAX],3	;
+	add	int ptr [EAX],7		;
+	
+ +

Struct/Union/Class Member Offsets

+ + To access members of an aggregate, given a pointer to the aggregate + is in a register, use the qualified name of the member: + +
+	struct Foo { int a,b,c; }
+	int bar(Foo *f)
+	{
+	    asm
+	    {	mov	EBX,f		;
+		mov	EAX,Foo.b[EBX]	;
+	    }
+	}
+	
+ +

Special Symbols

+ +
+ +
$ +
Represents the program counter of the start of the next + instruction. So, + +
+	jmp	$  ;
+ + branches to the instruction following the jmp instruction. +

+ +

__LOCAL_SIZE +
This gets replaced by the number of local bytes in the local + stack frame. It is most handy when the naked is invoked + and a custom stack frame is programmed. + +
+ +

Opcodes Supported

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
aaaaadaamaasadc
addaddpdaddpsaddsdaddss
andandnpdandnpsandpdandps
arplboundbsfbsrbswap
btbtcbtrbtscall
cbwcdqclccldclflush
clicltscmccmovacmovae
cmovbcmovbecmovccmovecmovg
cmovgecmovlcmovlecmovnacmovnae
cmovnbcmovnbecmovnccmovnecmovng
cmovngecmovnlcmovnlecmovnocmovnp
cmovnscmovnzcmovocmovpcmovpe
cmovpocmovscmovzcmpcmppd
cmppscmpscmpsbcmpsdcmpss
cmpswcmpxch8bcmpxchgcomisdcomiss
cpuidcvtdq2pdcvtdq2pscvtpd2dqcvtpd2pi
cvtpd2pscvtpi2pdcvtpi2pscvtps2dqcvtps2pd
cvtps2picvtsd2sicvtsd2sscvtsi2sdcvtsi2ss
cvtss2sdcvtss2sicvttpd2dqcvttpd2picvttps2dq
cvttps2picvttsd2sicvttss2sicwdcwde
dadaadasdbdd
dedecdfdidiv
divpddivpsdivsddivssdl
dqdsdtdwemms
enterf2xm1fabsfaddfaddp
fbldfbstpfchsfclexfcmovb
fcmovbefcmovefcmovnbfcmovnbefcmovne
fcmovnufcmovufcomfcomifcomip
fcompfcomppfcosfdecstpfdisi
fdivfdivpfdivrfdivrpfeni
ffreefiaddficomficompfidiv
fidivrfildfimulfincstpfinit
fistfistpfisubfisubrfld
fld1fldcwfldenvfldl2efldl2t
fldlg2fldln2fldpifldzfmul
fmulpfnclexfndisifnenifninit
fnopfnsavefnstcwfnstenvfnstsw
fpatanfpremfprem1fptanfrndint
frstorfsavefscalefsetpmfsin
fsincosfsqrtfstfstcwfstenv
fstpfstswfsubfsubpfsubr
fsubrpftstfucomfucomifucomip
fucompfucomppfwaitfxamfxch
fxrstorfxsavefxtractfyl2xfyl2xp1
hltidivimulininc
insinsbinsdinswint
intoinvdinvlpgiretiretd
jajaejbjbejc
jcxzjejecxzjgjge
jljlejmpjnajnae
jnbjnbejncjnejng
jngejnljnlejnojnp
jnsjnzjojpjpe
jpojsjzlahflar
ldmxcsrldslealeaveles
lfencelfslgdtlgslidt
lldtlmswlocklodslodsb
lodsdlodswlooploopeloopne
loopnzloopzlsllssltr
maskmovdqumaskmovqmaxpdmaxpsmaxsd
maxssmfenceminpdminpsminsd
minssmovmovapdmovapsmovd
movdq2qmovdqamovdqumovhlpsmovhpd
movhpsmovlhpsmovlpdmovlpsmovmskpd
movmskpsmovntdqmovntimovntpdmovntps
movntqmovqmovq2dqmovsmovsb
movsdmovssmovswmovsxmovupd
movupsmovzxmulmulpdmulps
mulsdmulssnegnopnot
ororpdorpsoutouts
outsboutsdoutswpackssdwpacksswb
packuswbpaddbpadddpaddqpaddsb
paddswpaddusbpadduswpaddwpand
pandnpavgbpavgwpcmpeqbpcmpeqd
pcmpeqwpcmpgtbpcmpgtdpcmpgtwpextrw
pinsrwpmaddwdpmaxswpmaxubpminsw
pminubpmovmskbpmulhuwpmulhwpmullw
pmuludqpoppopapopadpopf
popfdporprefetchntaprefetcht0prefetcht1
prefetcht2psadbwpshufdpshufhwpshuflw
pshufwpslldpslldqpsllqpsllw
psradpsrawpsrldpsrldqpsrlq
psrlwpsubbpsubdpsubqpsubsb
psubswpsubusbpsubuswpsubwpunpckhbw
punpckhdqpunpckhqdqpunpckhwdpunpcklbwpunpckldq
punpcklqdqpunpcklwdpushpushapushad
pushfpushfdpxorrclrcpps
rcpssrcrrdmsrrdpmcrdtsc
repreperepnerepnzrepz
retretfrolrorrsm
rsqrtpsrsqrtsssahfsalsar
sbbscasscasbscasdscasw
setasetaesetbsetbesetc
setesetgsetgesetlsetle
setnasetnaesetnbsetnbesetnc
setnesetngsetngesetnlsetnle
setnosetnpsetnssetnzseto
setpsetpesetposetssetz
sfencesgdtshlshldshr
shrdshufpdshufpssidtsldt
smswsqrtpdsqrtpssqrtsdsqrtss
stcstdstistmxcsrstos
stosbstosdstoswstrsub
subpdsubpssubsdsubsssysenter
sysexittestucomisducomissud2
unpckhpdunpckhpsunpcklpdunpcklpsverr
verwwaitwbinvdwrmsrxadd
xchgxlatxlatbxorxorpd
xorps
+ +

Pentium 4 (Prescott) Opcodes Supported

+ + + + + + + + + + + + + + + + + + + + + + +
addsubpdaddsubpsfisttphaddpdhaddps
hsubpdhsubpslddqumonitormovddup
movshdupmovsldupmwait
+ +

AMD Opcodes Supported

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pavgusbpf2idpfaccpfaddpfcmpeq
pfcmpgepfcmpgtpfmaxpfminpfmul
pfnaccpfpnaccpfrcppfrcpit1pfrcpit2
pfrsqit1pfrsqrtpfsubpfsubrpi2fd
pmulhrwpswapd
+ +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/interface.html dmd-0.124/dmd/html/d/interface.html --- dmd-0.123/dmd/html/d/interface.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/interface.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,384 +1,416 @@ - - - - - -Digital Mars - Interfacing to C - - - -www.digitalmars.com -[Home] -[Search] -[D] -

Last update Feb 10, 2005 -


- -

Interfacing to C

- - D is designed to fit comfortably with a C compiler for the target - system. D makes up for not having its own VM by relying on the - target environment's C runtime library. It would be senseless to - attempt to port to D or write D wrappers for the vast array of C APIs - available. How much easier it is to just call them directly. -

- - This is done by matching the C compiler's data types, layouts, - and function call/return sequences. - -

Calling C Functions

- - C functions can be called directly from D. There is no need for - wrapper functions, argument swizzling, and the C functions do not - need to be put into a separate DLL. -

- - The C function must be declared and given a calling convention, - most likely the "C" calling convention, for example: - -

-	extern (C) int strcmp(char* string1, char* string2);
-	
- - and then it can be called within D code in the obvious way: - -
-	import std.string;
-	int myDfunction(char[] s)
-	{
-	    return strcmp(std.string.toStringz(s), "foo");
-	}
-	
- - There are several things going on here: - - - - C code can correspondingly call D functions, if the D functions - use an attribute that is compatible with the C compiler, most likely - the extern (C): - -
-	// myfunc() can be called from any C function
-	extern (C)
-	{
-	    void myfunc(int a, int b)
-	    {
-		...
-	    }
-	}
-	
- -

Storage Allocation

- - C code explicitly manages memory with calls to malloc() and - free(). D allocates memory using the D garbage collector, - so no explicit free's are necessary. -

- - D can still explicitly allocate memory using c.stdlib.malloc() - and c.stdlib.free(), these are useful for connecting to C - functions that expect malloc'd buffers, etc. -

- - If pointers to D garbage collector allocated memory are passed to - C functions, it's critical to ensure that that memory will not - be collected by the garbage collector before the C function is - done with it. This is accomplished by: - -

- - An interior pointer to the allocated memory block is sufficient - to let the GC - know the object is in use; i.e. it is not necessary to maintain - a pointer to the beginning of the allocated memory. -

- - The garbage collector does not scan the stacks of threads not - created by the D Thread interface. Nor does it scan the data - segments of other DLL's, etc. - -

Data Type Compatibility

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
D typeC type
voidvoid
bitno equivalent
bytesigned char
ubyteunsigned char
charchar (chars are unsigned in D)
wcharwchar_t (when sizeof(wchar_t) is 2)
dcharwchar_t (when sizeof(wchar_t) is 4)
shortshort
ushortunsigned short
intint
uintunsigned
longlong long
ulongunsigned long long
floatfloat
doubledouble
reallong double
ifloatfloat _Imaginary
idoubledouble _Imaginary
ireallong double _Imaginary
cfloatfloat _Complex
cdoubledouble _Complex
creallong double _Complex
structstruct
unionunion
enumenum
classno equivalent
type*type *
type[dim]type[dim]
type[dim]*type(*)[dim]
type[]no equivalent
type[type]no equivalent
type function(parameters)type(*)(parameters)
type delegate(parameters)no equivalent
-

- - These equivalents hold for most 32 bit C compilers. The C standard - does not pin down the sizes of the types, so some care is needed. - -

Calling printf()

- - This mostly means checking that the printf format specifier - matches the corresponding D data type. - Although printf is designed to handle 0 terminated strings, - not D dynamic arrays of chars, it turns out that since D - dynamic arrays are a length followed by a pointer to the data, - the %.*s format works perfectly: - -
-	void foo(char[] string)
-	{
-	    printf("my string is: %.*s\n", string);
-	}
-	
- - The printf format string literal - in the example doesn't end with \0. This is because string literals, - when they are not part of an initializer to a larger data structure, - have a \0 character helpfully stored after the end of them. -

- - An improved D function for formatted output is - std.stdio.writef(). - -

Structs and Unions

- - D structs and unions are analogous to C's. -

- - C code often adjusts the alignment and packing of struct members - with a command line switch or with various implementation specific - #pragma's. D supports explicit alignment attributes that correspond - to the C compiler's rules. Check what alignment the C code is using, - and explicitly set it for the D struct declaration. -

- - D does not support bit fields. If needed, they can be emulated - with shift and mask operations. - -


Interfacing to C++

- - D does not provide an interface to C++. Since D, however, - interfaces directly to C, it can interface directly to - C++ code if it is declared as having C linkage. -

- - D class objects are incompatible with C++ class objects. - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright (c) 1999-2005 by Digital Mars, All Rights Reserved - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language - Interfacing to C + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +
+ + +

Interfacing to C

+ + D is designed to fit comfortably with a C compiler for the target + system. D makes up for not having its own VM by relying on the + target environment's C runtime library. It would be senseless to + attempt to port to D or write D wrappers for the vast array of C APIs + available. How much easier it is to just call them directly. +

+ + This is done by matching the C compiler's data types, layouts, + and function call/return sequences. + +

Calling C Functions

+ + C functions can be called directly from D. There is no need for + wrapper functions, argument swizzling, and the C functions do not + need to be put into a separate DLL. +

+ + The C function must be declared and given a calling convention, + most likely the "C" calling convention, for example: + +

+
+

+	extern (C) int strcmp(char* string1, char* string2);
+	

+ + and then it can be called within D code in the obvious way: + +

+
+

+	import std.string;
+	int myDfunction(char[] s)
+	{
+	    return strcmp(std.string.toStringz(s), "foo");
+	}
+	

+ + There are several things going on here: + +

+ + C code can correspondingly call D functions, if the D functions + use an attribute that is compatible with the C compiler, most likely + the extern (C): + +

+
+

+	// myfunc() can be called from any C function
+	extern (C)
+	{
+	    void myfunc(int a, int b)
+	    {
+		...
+	    }
+	}
+	

+ +

Storage Allocation

+ + C code explicitly manages memory with calls to malloc() and + free(). D allocates memory using the D garbage collector, + so no explicit free's are necessary. +

+ + D can still explicitly allocate memory using c.stdlib.malloc() + and c.stdlib.free(), these are useful for connecting to C + functions that expect malloc'd buffers, etc. +

+ + If pointers to D garbage collector allocated memory are passed to + C functions, it's critical to ensure that that memory will not + be collected by the garbage collector before the C function is + done with it. This is accomplished by: + +

+ + An interior pointer to the allocated memory block is sufficient + to let the GC + know the object is in use; i.e. it is not necessary to maintain + a pointer to the beginning of the allocated memory. +

+ + The garbage collector does not scan the stacks of threads not + created by the D Thread interface. Nor does it scan the data + segments of other DLL's, etc. + +

Data Type Compatibility

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
D typeC type
voidvoid
bitno equivalent
bytesigned char
ubyteunsigned char
charchar (chars are unsigned in D)
wcharwchar_t (when sizeof(wchar_t) is 2)
dcharwchar_t (when sizeof(wchar_t) is 4)
shortshort
ushortunsigned short
intint
uintunsigned
longlong long
ulongunsigned long long
floatfloat
doubledouble
reallong double
ifloatfloat _Imaginary
idoubledouble _Imaginary
ireallong double _Imaginary
cfloatfloat _Complex
cdoubledouble _Complex
creallong double _Complex
structstruct
unionunion
enumenum
classno equivalent
type*type *
type[dim]type[dim]
type[dim]*type(*)[dim]
type[]no equivalent
type[type]no equivalent
type function(parameters)type(*)(parameters)
type delegate(parameters)no equivalent
+

+ + These equivalents hold for most 32 bit C compilers. The C standard + does not pin down the sizes of the types, so some care is needed. + +

Calling printf()

+ + This mostly means checking that the printf format specifier + matches the corresponding D data type. + Although printf is designed to handle 0 terminated strings, + not D dynamic arrays of chars, it turns out that since D + dynamic arrays are a length followed by a pointer to the data, + the %.*s format works perfectly: + +

+
+

+	void foo(char[] string)
+	{
+	    printf("my string is: %.*s\n", string);
+	}
+	

+ + The printf format string literal + in the example doesn't end with \0. This is because string literals, + when they are not part of an initializer to a larger data structure, + have a \0 character helpfully stored after the end of them. +

+ + An improved D function for formatted output is + std.stdio.writef(). + +

Structs and Unions

+ + D structs and unions are analogous to C's. +

+ + C code often adjusts the alignment and packing of struct members + with a command line switch or with various implementation specific + #pragma's. D supports explicit alignment attributes that correspond + to the C compiler's rules. Check what alignment the C code is using, + and explicitly set it for the D struct declaration. +

+ + D does not support bit fields. If needed, they can be emulated + with shift and mask operations. + +


Interfacing to C++

+ + D does not provide an interface to C++. Since D, however, + interfaces directly to C, it can interface directly to + C++ code if it is declared as having C linkage. +

+ + D class objects are incompatible with C++ class objects. + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/intro.html dmd-0.124/dmd/html/d/intro.html --- dmd-0.123/dmd/html/d/intro.html 2005-04-28 14:16:04.000000000 +0200 +++ dmd-0.124/dmd/html/d/intro.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,124 +1,133 @@ - - - -D Programming Language - - - - -www.digitalmars.com -[Home] -[Search] -[D] -
Last update Mar 4, 2005 -


- -

D Programming Language

- -"It seems to me that most of the "new" programming languages - fall into one of two categories: Those from academia with radical - new paradigms and those from large corporations with a focus on RAD - and the web. Maybe it's time for a new language born out of - practical experience implementing compilers." -- Michael -

-

- -"Great, just what I need.. another D in programming." -- Segfault -

-

- -This is the reference document for the D programming language. -D was conceived in December 1999 by myself as a reengineering of C and C++, -and has grown and evolved with helpful -suggestions and critiques by my friends and colleagues. -I've been told the usual, that there's no chance for a new programming -language, that who do I think I am designing a language, etc. Take a -look at the document and decide for yourself! -

- - Check out the quick comparison - of D with C, C++, C# and Java. -

- -The D newsgroup in -news.digitalmars.com - server is where discussions -of this should go. Suggestions, criticism, kudos, flames, etc., -are all welcome there. -Alternatively, try the -D forum. -There also may be a local D user group -in your community (or you can start one!). -

- - Download the current version - of the compiler for Win32 and x86 Linux and try it out! -

- David Friedman has integrated the - D frontend with GCC. -

- - Alternate versions of this document: - -

- - "D Language Perfect Guide" -

- - For SDWest 2004 I gave a - - presentation on D. -

- - Do you feel the - need for speed? -

- - Note: all D users agree that by downloading and using - D, or reading the D specs, - they will explicitly identify any claims to intellectual property - rights with a copyright or patent notice in any posted or emailed - feedback sent to Digital Mars. -

--Walter - -

Feedback and Comments

- - Add feedback and comments regarding this - page. - -
Copyright © 1999-2005 by Digital Mars, All Rights Reserved

- - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +D Programming Language + + + + +www.digitalmars.com + +Home +| Search +| D + +
+Last update Thu May 19 2005 +


+ +

D Programming Language

+ +"It seems to me that most of the "new" programming languages + fall into one of two categories: Those from academia with radical + new paradigms and those from large corporations with a focus on RAD + and the web. Maybe it's time for a new language born out of + practical experience implementing compilers." -- Michael +

+

+ +"Great, just what I need.. another D in programming." -- Segfault +

+

+ +This is the reference document for the D programming language. +D was conceived in December 1999 by myself as a reengineering of C and C++, +and has grown and evolved with helpful +suggestions and critiques by my friends and colleagues. +I've been told the usual, that there's no chance for a new programming +language, that who do I think I am designing a language, etc. Take a +look at the document and decide for yourself! +

+ + Check out the quick comparison + of D with C, C++, C# and Java. +

+ +The D newsgroup in +news.digitalmars.com + server is where discussions +of this should go. Suggestions, criticism, kudos, flames, etc., +are all welcome there. +Alternatively, try the +D forum. +There also may be a local D user group +in your community (or you can start one!). +

+ + Download the current version + of the compiler for Win32 and x86 Linux and try it out! +

+ David Friedman has integrated the + D frontend with GCC. +

+ + Alternate versions of this document: + +

+ + "D Language Perfect Guide" +

+ + For SDWest 2004 I gave a + + presentation on D. +

+ + Do you feel the + need for speed? +

+ + Note: all D users agree that by downloading and using + D, or reading the D specs, + they will explicitly identify any claims to intellectual property + rights with a copyright or patent notice in any posted or emailed + feedback sent to Digital Mars. +

+-Walter + +

Feedback and Comments

+ + Add feedback and comments regarding this + page. + +
+Copyright © 1999-2005 by Digital Mars, All Rights Reserved

+ + + + + diff -uNr dmd-0.123/dmd/html/d/lex.html dmd-0.124/dmd/html/d/lex.html --- dmd-0.123/dmd/html/d/lex.html 2005-04-15 14:13:42.000000000 +0200 +++ dmd-0.124/dmd/html/d/lex.html 2005-05-19 11:44:48.000000000 +0200 @@ -1,890 +1,945 @@ - - -D Programming Language - Lexical - - - -www.digitalmars.com - -[Home] -[Search] -[D] - -
Last update Apr 1, 2005 -


- -

Lexical

- - In D, the lexical analysis is independent of the syntax parsing and the - semantic analysis. The lexical analyzer splits the source text up into - tokens. The lexical grammar describes what those tokens are. The D - lexical grammar is designed to be suitable for high speed scanning, it - has a minimum of special case rules, there is only one phase of - translation, and to make it easy to write a correct scanner - for. The tokens are readily recognizable by those familiar with C and - C++. - -

Phases of Compilation

- - The process of compiling is divided into multiple phases. Each phase - has no dependence on subsequent phases. For example, the scanner is - not perturbed by the semantic analyzer. This separation of the passes - makes language tools like syntax - directed editors relatively easy to produce. - It also is possible to compress D source by storing it in - 'tokenized' form. - -
    -
  1. source character set
    - - The source file is checked to see what character set it is, - and the appropriate scanner is loaded. ASCII and UTF - formats are accepted. - -
  2. lexical analysis
    - - The source file is divided up into a sequence of tokens. - Special tokens are replaced with other tokens. - Special token sequences - are processed and removed. - -
  3. syntax analysis
    - - The sequence of tokens is parsed to form syntax trees. - -
  4. semantic analysis
    - - The syntax trees are traversed to declare variables, load symbol tables, assign - types, and in general determine the meaning of the program. - -
  5. optimization
    - - Optimization is an optional pass that tries to rewrite the program - in a semantically equivalent, but faster executing, version. - -
  6. code generation
    - - Instructions are selected from the target architecture to implement - the semantics of the program. The typical result will be - an object file, suitable for input to a linker. -
- - -

Source Text

- - D source text can be in one of the following formats: - - - - UTF-8 is a superset of traditional 7-bit ASCII. - One of the - following UTF BOMs (Byte Order Marks) can be present at the beginning - of the source text: -

- - - - - - - - - -
Format - BOM -
UTF-8 - EF BB BF -
UTF-16BE - FE FF -
UTF-16LE - FF FE -
UTF-32BE - 00 00 FE FF -
UTF-32LE - FF FE 00 00 -
ASCII - no BOM -
-

- - There are no digraphs or trigraphs in D. -

- - The source text consists of - white space, - end of lines, - comments, - special token sequences, - tokens, - all followed by end of file. -

- - The source text is split into tokens using the maximal munch - technique, i.e., the - lexical analyzer tries to make the longest token it can. For example - >> is a right shift token, - not two greater than tokens. - -

End of File

- -
-	EndOfFile:
-		physical end of the file
-		\u0000
-		\u001A
-	
- - The source text is terminated by whichever comes first. - -

End of Line

- -
-	EndOfLine:
-		\u000D
-		\u000A
-		\u000D \u000A
-		EndOfFile
-	
- - There is no backslash line splicing, nor are there any limits - on the length of a line. - -

White Space

- -
-	WhiteSpace:
-		Space
-		Space WhiteSpace
-
-	Space:
-		\u0020
-		\u0009
-		\u000B
-		\u000C
-		EndOfLine
-		Comment
-	
- - White space is defined as a sequence of one or more of spaces, - tabs, vertical tabs, form feeds, end of lines, or comments. - -

Comments

- -
-	Comment:
-		/* Characters */
-		// Characters EndOfLine
-		/+ Characters +/
-	
- - D has three kinds of comments: -
    -
  1. Block comments can span multiple lines, but do not nest. -
  2. Line comments terminate at the end of the line. -
  3. Nesting comments can span multiple lines and can nest. -
- - Comment processing conceptually happens before tokenization. - This means that - embedded strings and comments do not prevent recognition of - comment openings and closings: - -
-	a = /+ // +/ 1;		// parses as if 'a = 1;'
-	a = /+ "+/" +/ 1";	// parses as if 'a = " +/ 1";'
-	a = /+ /* +/ */ 3;	// parses as if 'a = */ 3;'
-	
- - Comments cannot be used as token concatenators, for example, - abc/**/def is two tokens, abc and def, - not one abcdef token. - -

Tokens

- -
-	Token:
-		Identifier
-		StringLiteral
-		CharacterLiteral
-		IntegerLiteral
-		FloatLiteral
-		Keyword
-		/
-		/=
-		.
-		..
-		...
-		&
-		&=
-		&&
-		|
-		|=
-		||
-		-
-		-=
-		--
-		+
-		+=
-		++
-		<
-		<=
-		<<
-		<<=
-		<>
-		<>=
-		>
-		>=
-		>>=
-		>>>=
-		>>
-		>>>
-		!
-		!=
-		!==
-		!<>
-		!<>=
-		!<
-		!<=
-		!>
-		!>=
-		(
-		)
-		[
-		]
-		{
-		}
-		?
-		,
-		;
-		:
-		$
-		=
-		==
-		===
-		*
-		*=
-		%
-		%=
-		^
-		^=
-		~
-		~=
-	
- -

Identifiers

- -
-	Identifier:
-		IdentiferStart
-		IdentiferStart IdentifierChars
-
-	IdentifierChars:
-		IdentiferChar
-		IdentiferChar IdentifierChars
-
-	IdentifierStart:
-		_
-		Letter
-		UniversalAlpha
-
-	IdentifierChar:
-		IdentiferStart
-		Digit
-	
- - - Identifiers start with a letter, _, or universal alpha, - and are followed by any number - of letters, _, digits, or universal alphas. - Universal alphas are as defined in ISO/IEC 9899:1999(E) Appendix D. - (This is the C99 Standard.) - Identifiers can be arbitrarily long, and are case sensitive. - Identifiers starting with __ (two underscores) are reserved. - -

String Literals

- -
-	StringLiteral:
-		WysiwygString
-		AlternateWysiwygString
-		DoubleQuotedString
-		EscapeSequence
-		HexString
-
-	WysiwygString:
-		r" WysiwygCharacters "
-
-	AlternateWysiwygString:
-		` WysiwygCharacters `
-
-	WysiwygCharacter:
-		Character
-		EndOfLine
-
-	DoubleQuotedString:
-		" DoubleQuotedCharacters "
-
-	DoubleQuotedCharacter:
-		Character
-		EscapeSequence
-		EndOfLine
-
-	EscapeSequence:
-		\'
-		\"
-		\?
-		\\
-		\a
-		\b
-		\f
-		\n
-		\r
-		\t
-		\v
-		\ EndOfFile
-		\x HexDigit HexDigit
-		\ OctalDigit
-		\ OctalDigit OctalDigit
-		\ OctalDigit OctalDigit OctalDigit
-		\u HexDigit HexDigit HexDigit HexDigit
-		\U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit
-		\& NamedCharacterEntity ;
-
-	HexString:
-		x" HexStringChars "
-
-	HexStringChar
-		HexDigit
-		WhiteSpace
-		EndOfLine
-	
- - A string literal is either a double quoted string, a wysiwyg quoted - string, an escape sequence, or a hex string. -

- - Wysiwyg quoted strings are enclosed by r" and ". - All characters between - the r" and " are part of the string except for EndOfLine which is - regarded as a single \n character. - There are no escape sequences inside r" ": - -

-	r"hello"
-	r"c:\root\foo.exe"
-	r"ab\n"			string is 4 characters, 'a', 'b', '\', 'n'
-	
- - An alternate form of wysiwyg strings are enclosed by backquotes, - the ` character. The ` character is not available on some keyboards - and the font rendering of it is sometimes indistinguishable from - the regular ' character. Since, however, the ` is rarely used, - it is useful to delineate strings with " in them. - -
-	`hello`
-	`c:\root\foo.exe`
-	`ab\n`			string is 4 characters, 'a', 'b', '\', 'n'
-	
- -